Exploratory Analysis
Total Number of Bookings per Borough

Manhattan and Brooklyn both by far the most popular areas for Airbnb
listings.
Two central Boroughs which may indicate the main reason people book
is for holidays / Tourism.
Average Price per Neighbourhood Group
# Average Price per Room
price_per_room <- prices_df %>%
# group by room_type
group_by(room_type) %>%
# return average price per room_type
summarise(avg_price = mean(price)) %>%
# create bar chart to visualise result
ggplot(aes(room_type, avg_price, fill = room_type)) +
# specify bar chart
geom_col(show.legend = FALSE) +
# annotate each bar
geom_label(mapping = aes(label = round(avg_price, 2)), size = 6,
fill = "#F5FFFA", fontface = "bold",
# position change to make sure label stays on page
position = position_stack(vjust = 0.9)) +
# add theme
theme_classic() +
# titles
labs(x = "Room Type", y = "Average Price ($)",
title = "Average Price by Room Type")
# Average price per neighbourhood group
price_room_borough <- prices_df %>%
# group by both neighbourhood and room_type
group_by(neighbourhood_group, room_type) %>%
# return average price for each room type in each neighbourhood
summarise(avg_price = mean(price)) %>%
# sort from highest to lowest price
arrange(desc(avg_price)) %>%
# create bar chart
ggplot(aes(reorder(neighbourhood_group, avg_price), avg_price,
fill = room_type)) +
# specify bar chart
geom_col(show.legend = FALSE) +
# annotate bars
geom_label(mapping = aes(label = round(avg_price, 2)), size = 2.5,
fill = "#F5FFFA", fontface = "bold", hjust = 0.5,
# position change to make sure label stays on page
position = position_stack(vjust = 0.9)) +
# theme
theme_classic() +
# titles
labs(x = "New York Boroughs", y = "Average Price ($)",
title = "Average Price per Borough by Room Type") +
# split into room_types
facet_wrap(~room_type) +
# flip x and y axis
coord_flip()
`summarise()` has grouped output by 'neighbourhood_group'. You can override using the `.groups` argument.
# plot both visualisations together
cowplot::plot_grid(price_per_room, price_room_borough, nrow = 2)

The 10 most expensive and cheapest New York Districts
# Top 10 most expensive districts on average
a <- prices_df %>%
# group by individual districts within neighbourhoods
group_by(neighbourhood) %>%
# return average price
summarise(avg_price = mean(price)) %>%
# sort from highest to lowest
arrange(desc(avg_price)) %>%
# return the top 10 (out of 218)
slice(1:10) %>%
# create bar plot
ggplot(aes(reorder(neighbourhood, avg_price), avg_price,
fill = neighbourhood)) +
# specify bar chart
geom_col(show.legend = FALSE) +
# annotate bars
geom_label(mapping = aes(label = round(avg_price, 2)), size = 3,
fill = "#F5FFFA", fontface = "bold") +
# theme
theme_classic() +
# change x-axis label position
theme(axis.text.x = element_text(angle = 30, vjust = 0.95, hjust = 1)) +
# titles
labs(x = "Neighbourhood", y = "Average Price ($)",
title = "The 10 Most Expensive Districts on Average")
# top 10 least expensive districts on average
b <- prices_df %>%
# group by individual districts within neighbourhoods
group_by(neighbourhood) %>%
# return average prices
summarise(avg_price = mean(price)) %>%
# arrange from lowest to highest
arrange(avg_price) %>%
# return bottom 10 prices
slice(1:10) %>%
# create bar chart
ggplot(aes(reorder(neighbourhood, avg_price), avg_price,
fill = neighbourhood)) +
# specify bar chart
geom_col(show.legend = FALSE) +
# annotate bars
geom_label(mapping = aes(label = round(avg_price, 2)), size = 3,
fill = "#F5FFFA", fontface = "bold") +
# theme
theme_classic() +
# change x-axis label position
theme(axis.text.x = element_text(angle = 30, vjust = 0.95, hjust = 1)) +
# titles
labs(x = "Neighbourhood", y = "Average Price ($)",
title = "The 10 Least Expensive Districts on Average")
# add plots into the same output
cowplot::plot_grid(a, b, nrow=2)

The 10 most expensive districts are all located in Manhattan apart
from, Neponsit (Queens) and WillowBrook (Staten Island)
The majority of the 10 least expensive districts reside in the Bronx,
State Island and Queens
Average Reviews by Last Month Review Submitted

Suggests that most people are leaving reviews in the summer,
indicating some seasonality to Airbnb booking in New York.
Price Density by Area
# price density by New York Borough
ggplot(
# create plot for price less than $500
subset(prices_df, price < 500),aes(x = price)) +
# specify density plot
geom_density(
mapping = aes(fill = neighbourhood_group),
bandwidth = 100, alpha = 1, size = 0.5, show.legend = FALSE) +
# theme
theme_bw() +
# show individual density plots for boroughs
facet_wrap(~neighbourhood_group) +
# titles
labs(x = "Price", y = "Density", title = "Price Density by Borough")
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.Warning: Ignoring unknown parameters: `bandwidth`

Pricing density plot reveals that boroughs with fewer amount of
bookings (Queens, Staten Island and Bronx) have a higher density of
lower prices
Most common areas (Mahattan and Brooklyn) have a wider density plot
indicating that prices vary more.
Text Mining
I want to find the words that are associated with different price
ranges.
So I need to create new variables which classify the price range of
each airbnb
we will define price ranges based around the average price for total
bookings
mean price is $142 therefore, low will be less than $100, medium will
be between $100 - $200, high will be $200 - $300 and very high will be
greater than $300
High/Very High Price Range
# words associated with high prices
high_price_words <- prices_new %>%
# filter for High and Very High price classes
filter(price_class %in% c("High", "Very High")) %>%
# take individual words from the name column
unnest_tokens(word, name) %>%
# take out stop_words
anti_join(stop_words) %>%
# select word column
dplyr::select(word)
Joining, by = "word"
# most common words
sorted_hp_words <- high_price_words %>%
# sort most common words
count(word, sort = TRUE)
# create word cloud for high/very high price Airbnbs
wordcloud(
# words to use for word cloud
words = sorted_hp_words$word,
# number of times these words appear
freq = sorted_hp_words$n,
# maximum number of words used
max.words=60,
# no random order
random.order=FALSE,
# proportion of words with a 90 degree angle
rot.per=0.35,
# add colour palette
colors=brewer.pal(8, "Spectral"))

Words that stand out from wordcloud include: bedroom, apartment,
village, luxury, location, Manhattan, spacious, park - start to
understand what kind of Airbnbs are being advertised for high prices
Low Price Range
# words associated with low prices
low_price_words <- prices_new %>%
# filter for rows associated with low prices
filter(price_class %in% "Low") %>%
# take words from name column
unnest_tokens(word, name) %>%
# remove stop words
anti_join(stop_words) %>%
# select word column
dplyr::select(word)
Joining, by = "word"
# most common words
sorted_lp_words <- low_price_words %>%
# sort most common words
count(word, sort = TRUE)
wordcloud(
# select words
words = sorted_lp_words$word,
# number of times these words appear
freq = sorted_lp_words$n,
# maximum number of words in cloud
max.words=60,
# no random order
random.order=FALSE,
# proportion of words rotated
rot.per=0.35,
# colour palette
colors=brewer.pal(8, "Spectral"))

when we look at the word cloud of the low price range, we see some
similarities with the high price range indicating owners are trying to
sell the property as up market.
Big emphasis on property being “private” which is likely to be a big
concern for people when not paying that much. In contrast, privacy is a
given when paying for high end accommodation.
Medium Price Range
# words associated with medium price range (around the average)
medium_price_words <- prices_new %>%
# filter rows associated with medium price range
filter(price_class %in% "Medium") %>%
# select words from name column
unnest_tokens(word, name) %>%
# remove stop words
anti_join(stop_words) %>%
# select words
dplyr::select(word)
Joining, by = "word"
# most common words
sorted_mp_words <- medium_price_words %>%
# sort words
count(word, sort = TRUE)
# word cloud for medium price range
wordcloud(
# words to use
words = sorted_mp_words$word,
# frequency words appear
freq = sorted_mp_words$n,
# maximum number of words
max.words=60,
# random order = FALSE --> makes it neat
random.order=FALSE,
# proportion of words rotated
rot.per=0.35,
# colour palette
colors=brewer.pal(8, "Spectral"))

Not a tremendous amount of difference here, probably as expected it
takes a balance between low and high price ranges highlighting privacy
as important but also more emphasis on location.
Most Popular Bigrams used in Airbnb Name
Analysis of the most popular word combinations
# Obtain the 2 word bigrams
bigram_names <- prices_new %>%
unnest_tokens(bigram, name, token = "ngrams", n = 2)
# Separate into two words
bigrams_separated <- bigram_names %>%
separate(bigram, c("word1", "word2"), sep = " ")
# filter the words for stop words
bigrams_filtered <- bigrams_separated %>%
# filter words NOT IN stop words
filter(!word1 %in% stop_words$word) %>%
filter(!word2 %in% stop_words$word)
# count and sort the most popular words
bigrams_counts <- bigrams_filtered %>%
count(word1, word2, sort = TRUE)
# most popular bigrams graph
bigrams_counts %>%
# filter out numbers
filter(!str_detect(word1, "[0-9]")) %>%
# unite both word columns
unite(col = "bigrams", c("word1", "word2"), sep = " ", remove = TRUE) %>%
# get top 10
slice(1:10) %>%
# visualise
ggplot(aes(reorder(bigrams, n), n, fill = bigrams)) +
# specify bar graph
geom_col(show.legend = FALSE) +
# flip x and y-axis
coord_flip() +
# theme
theme_bw() +
# annotate each bar
geom_label(mapping = aes(label = n), size = 3,
fill = "#F5FFFA", fontface = "bold") +
# titles
labs(y = "Number of Bigram Mentions", x = "Bigram",
title = "Most Popular Bigrams in Airbnb Name")

Hosts emphasis on location is a common strategy to entice
consumers
consumers want to be closer to famous landmarks.
Model Building - Linear Regression
Approach: - manual - good way to become familiar with data - avoid
over or under fitting the model
Goals of the model:
- A well fit model that reasonably explains variance in price
- satisfies assumptions needed to validate model
- Be able to output statistically significant coefficients for
consumer/host recommendations
Distribution of Price
Dependent variable: Price
Important to investigate its distribution as it may require a
transformation to create a better fit for the model

Price is heavily skewed to the right indicates a log transformation
is needed to get a normal bell shaped distribution
# mean price
mean_price <- prices_new %>%
summarise(m_price = mean(price))
# log bell shaped distribution
prices_new %>%
# set price on x-axis as a natural logarithm
ggplot(aes(log(price))) +
# specify histogram
geom_histogram(bins = 40, aes(y = ..density..), fill = "red") +
# insert density area
geom_density(alpha = 0.2, fill = "red") +
# insert line to indicate average
geom_vline(data = mean_price, aes(xintercept = log(m_price)), size = 1,
linetype = 2) +
# theme
theme_bw() +
# title
labs(title = "Distribution of log(price)")

Finalising Data for Model
Dropped variables:
- ‘name’ - use dummy variables for important words and bigrams
instead
- ‘neighbourhood’ - use the categorical variable for five New York
Boroughs
- ‘price_class’ - high correlated with dependent variable price
Dummy variables created from text analysis:
- ‘apartment’
- ‘private’
- ‘central park’
prices_reg_df <- prices_new %>%
# create dummy variables for chosen words that may impact price
mutate(apartment_ad = if_else(str_detect(name, "[Aa]partment"), "YES", "NO"),
private_ad = if_else(str_detect(name, "[Pp]rivate"), "YES", "NO"),
central_park_ad = if_else(str_detect(name, "[Cc]entral [Pp]ark"),
"YES", "NO"),
) %>%
# remove variables not considered for model
dplyr::select(-c(name, neighbourhood, price_class)) %>%
# log transform price
mutate(log_price = log(price + 1)) %>%
# bring price to the front
dplyr::select(log_price,price, everything()) %>%
# change all character variables to factor
mutate(across(.cols = is.character,
.fns = as_factor)) %>%
# remove original price variable
dplyr::select(-price)
Check alias() function to check for multicollinearity
# check for multicollinearity
alias(lm(log_price ~ ., data = prices_reg_df))
Model :
log_price ~ neighbourhood_group + latitude + longitude + room_type +
minimum_nights + number_of_reviews + reviews_per_month +
calculated_host_listings_count + availability_365 + last_review_month +
name_length + apartment_ad + private_ad + central_park_ad
Data is now ready to be used in regression analysis
Use ggpairs() to investigate which variables are highly correlated
with price.
Data set is large so relationship analysis will be divided into
numeric and non-numeric datatypes
# select variables that are numeric
variable_numeric <- prices_reg_df %>%
select_if(is.numeric)
# ggpairs with only numeric variables
ggpairs(variable_numeric)

# select variables that are categorical
variable_nonnumeric <- prices_reg_df %>%
# use function to return variables that are categorical
select_if(function(x) !is.numeric(x))
# need to add log_price to non-numeric data
variable_nonnumeric$log_price <- prices_reg_df$log_price
# non-numeric ggpairs
ggpairs(variable_nonnumeric)

Univariate Regression
Largest correlation with price: longitude - negatively correlated by
0.155 - statistically significant at the 0.001 level of
significance.
The non-numeric ggpairs suggests that several variables will be able
to explain price variance.
relationship between log(price) and longitude

create model
# linear regression model
model_1 <- lm(log_price ~ longitude, data = prices_reg_df)

Regression Diagnostics
graph 1 (population) - tell us most observations are independence,
blue line declines at the end indicating other chunk of observations are
not independently distributed. Need another variable.
graph 2 (distribution) - shows a fairly normal distribution, again, a
bend at the end indicates model needs more to give a better
distribution
graph 3 (homoskedasticity) - There is heteroskedasticity in the model
indicated my curve on blue line
graph 4 (outliers) - There is a small number of outliers, and points
are not highly leveraged.
model interpretation
# obtain results of regression model
summary(model_1)
Call:
lm(formula = log_price ~ longitude, data = prices_reg_df)
Residuals:
Min 1Q Median 3Q Max
-4.7215 -0.4287 -0.0309 0.3813 4.6629
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -335.83166 5.02723 -66.80 <2e-16 ***
longitude -4.60491 0.06798 -67.74 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.6256 on 38835 degrees of freedom
Multiple R-squared: 0.1057, Adjusted R-squared: 0.1056
F-statistic: 4589 on 1 and 38835 DF, p-value: < 2.2e-16
coefficient:
- An increase in longitude by one unit is associated with a change in
price by 99.9% on average.
R-squared - longitude explains 10.6% of the variance of airbnb
price.
Multivariate Regression
From the ggpairs plot and previous analysis, neighbourhood_group is
suggests having an impact on airbnb prices, I will add this next.
Relationship between Price and Borough


regression diagnostics
graph 1 - independent population (achieved) graph 2 - still a skew in
distribution graph 3 - Homoskdasticity (achieved) graph 4 - No highly
leveraged points, but there are still (potentially) a few outliers
model interpretation
# regression results
summary(model_2)
Call:
lm(formula = log_price ~ longitude + neighbourhood_group, data = prices_reg_df)
Residuals:
Min 1Q Median 3Q Max
-4.5931 -0.4275 -0.0334 0.3609 4.6367
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -3.283e+02 7.499e+00 -43.780 < 2e-16 ***
longitude -4.501e+00 1.014e-01 -44.391 < 2e-16 ***
neighbourhood_groupManhattan 2.790e-01 7.033e-03 39.667 < 2e-16 ***
neighbourhood_groupQueens 1.506e-01 1.294e-02 11.643 < 2e-16 ***
neighbourhood_groupStaten Island -9.425e-01 3.777e-02 -24.956 < 2e-16 ***
neighbourhood_groupBronx -6.477e-02 2.201e-02 -2.942 0.00326 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.6038 on 38831 degrees of freedom
Multiple R-squared: 0.167, Adjusted R-squared: 0.1669
F-statistic: 1557 on 5 and 38831 DF, p-value: < 2.2e-16
coefficients:
all statistically significant at levels of significance - can
reject the null hypothesis and say that coefficients are statistically
different from zero.
An increase in Manhattan by one unit (zero to one) is associated
with a change in price by (e^0.27-1) * 100 = 31%,
holding all other factors constant
An increase in Staten Island by one unit (zero to one) is
associated with a change in price by (e^-0.94 - 1) * 100 =
-60.9%, holding all other factors constant
Anova function
# function to check if dummy variables are useful
anova(model_1, model_2)
Analysis of Variance Table
Model 1: log_price ~ longitude
Model 2: log_price ~ longitude + neighbourhood_group
Res.Df RSS Df Sum of Sq F Pr(>F)
1 38835 15198
2 38831 14156 4 1042.4 714.85 < 2.2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
anova function confirms the neighbourhood_group dummy variable was
good to include in the model.
Model 3
before adding a new variable, must check the residuals of this model
against the remaining variables in the dataset
check residuals

# non-numeric ggpairs
ggpairs(price_resid_nonnumeric)
From numeric variables, availability_365 has the highest correlation
with price a positive correlation of 0.131 (statistically
significant).
However, the non-numeric variables indicate that room type may
present a better explanation of price variance.
Comparison between impact of Room Type and Availability on
Price
avail_plot <- price_resid_numeric %>%
ggplot(aes(availability_365, resid)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, colour = "red") +
theme_bw() +
labs(x = "Yearly Room Availability", y = "Residuals",
title = "Relationship Residuals and Availability") +
theme(plot.title = element_text(size=10))
room_type_plot <- price_resid_nonnumeric %>%
ggplot(aes(room_type, resid, fill = room_type)) +
geom_boxplot(show.legend = FALSE) +
theme_bw() +
labs(title = "Relationship Residuals and Room Type",
x = "Room Type", y = "Residuals") +
theme(plot.title = element_text(size=10))
cowplot::plot_grid(avail_plot, room_type_plot, nrow = 1)
`geom_smooth()` using formula = 'y ~ x'

The comparison suggests room type should offer more explanation.

graph 1 - residuals are independent graph 2 - the residuals seem to
be increasingly not distributed around zero with more skew at the
beginning and end graph 3 - conditional variance of residuals is
constant (homoskedasticity)
# model results
summary(model_3)
Call:
lm(formula = log_price ~ longitude + neighbourhood_group + room_type,
data = prices_reg_df)
Residuals:
Min 1Q Median 3Q Max
-4.9468 -0.2982 -0.0401 0.2313 4.9777
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -2.133e+02 5.899e+00 -36.160 < 2e-16 ***
longitude -2.942e+00 7.978e-02 -36.873 < 2e-16 ***
neighbourhood_groupManhattan 2.397e-01 5.495e-03 43.611 < 2e-16 ***
neighbourhood_groupQueens 1.183e-01 1.010e-02 11.709 < 2e-16 ***
neighbourhood_groupStaten Island -6.894e-01 2.951e-02 -23.358 < 2e-16 ***
neighbourhood_groupBronx -5.006e-02 1.718e-02 -2.914 0.00357 **
room_typeEntire home/apt 7.443e-01 4.943e-03 150.572 < 2e-16 ***
room_typeShared room -3.956e-01 1.659e-02 -23.841 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4711 on 38829 degrees of freedom
Multiple R-squared: 0.493, Adjusted R-squared: 0.4929
F-statistic: 5393 on 7 and 38829 DF, p-value: < 2.2e-16
As anticipated, room_type greatly enhanced the explanation of the
model. The R-squared suggests the model explains 49.3% of the variance
in price.
The variable coefficients are all statistically significant therefore
can be interpreted.
Model 4
Check residuals


As before, availability is displaying by far the strongest
correlation, and there does not seem to be any stand out non-numeric
variables. Therefore, room availability will be used in the next
model.

graph 1 - model population is independently distributed graph 2 -
still skew at both ends of graph, indicating graph is only somewhat
normally distributed graph 3 - conditional variance of residuals is
constant (homoskedastic)
# model results
summary(model_4)
Call:
lm(formula = log_price ~ longitude + neighbourhood_group + room_type +
availability_365, data = prices_reg_df)
Residuals:
Min 1Q Median 3Q Max
-4.9243 -0.2919 -0.0406 0.2328 5.0684
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -2.274e+02 5.815e+00 -39.107 < 2e-16 ***
longitude -3.131e+00 7.863e-02 -39.819 < 2e-16 ***
neighbourhood_groupManhattan 2.332e-01 5.408e-03 43.122 < 2e-16 ***
neighbourhood_groupQueens 1.041e-01 9.943e-03 10.466 < 2e-16 ***
neighbourhood_groupStaten Island -7.852e-01 2.915e-02 -26.939 < 2e-16 ***
neighbourhood_groupBronx -7.984e-02 1.692e-02 -4.719 2.38e-06 ***
room_typeEntire home/apt 7.438e-01 4.861e-03 153.004 < 2e-16 ***
room_typeShared room -4.276e-01 1.634e-02 -26.166 < 2e-16 ***
availability_365 6.674e-04 1.840e-05 36.271 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4633 on 38828 degrees of freedom
Multiple R-squared: 0.5096, Adjusted R-squared: 0.5095
F-statistic: 5043 on 8 and 38828 DF, p-value: < 2.2e-16
R-squared has only increased marginally to 0.51 - model explains 51%
of the variance in price
All variables in the model are statistically significant
Adding an interaction term
potential terms:
- longitude:neighbourhood_group
- longitude:room_type
- longitude:availability_365
- neighbourhood_group:room_type
- neighbourhood_group:availability_365
- room_type:availability_365
Through process of elimination, longitude:neighbourhood_group
Plotting the interaction
# add model residuals to data
price_resid <- prices_reg_df %>%
# add model residuals
add_residuals(model_5) %>%
# remove log_price
dplyr::select(-log_price)
# check the interaction between longitude and neighbourhood_group
coplot(resid ~ longitude | neighbourhood_group,
# give an action to be carried out in each panel
panel = function(x, y, ...){
# plot coordinates of x and y
points(x, y)
# insert linear model line
abline(lm(y ~ x), col = "blue")
},
data = price_resid, rows = 1)

Model Diagnostics

graph 1 - population is independent graph 2 - model still not
completely evenly distributed around 0 graph 3 - conditional variance of
residuals is constant (homoskedasticity) graph 4 - there are still some
outliers, but no highly leveraged points
Model Summary
# model results
summary(model_5)
Call:
lm(formula = log_price ~ longitude + neighbourhood_group + room_type +
availability_365 + longitude:neighbourhood_group, data = prices_reg_df)
Residuals:
Min 1Q Median 3Q Max
-4.9155 -0.2856 -0.0436 0.2300 5.1577
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -2.378e+02 1.031e+01 -23.065 < 2e-16 ***
longitude -3.272e+00 1.394e-01 -23.468 < 2e-16 ***
neighbourhood_groupManhattan -3.219e+02 1.557e+01 -20.677 < 2e-16 ***
neighbourhood_groupQueens 1.761e+02 1.349e+01 13.053 < 2e-16 ***
neighbourhood_groupStaten Island 3.119e+02 5.582e+01 5.587 2.33e-08 ***
neighbourhood_groupBronx 2.388e+02 3.601e+01 6.631 3.38e-11 ***
room_typeEntire home/apt 7.255e-01 4.820e-03 150.506 < 2e-16 ***
room_typeShared room -4.263e-01 1.609e-02 -26.491 < 2e-16 ***
availability_365 6.323e-04 1.815e-05 34.842 < 2e-16 ***
longitude:neighbourhood_groupManhattan -4.354e+00 2.105e-01 -20.689 < 2e-16 ***
longitude:neighbourhood_groupQueens 2.382e+00 1.825e-01 13.053 < 2e-16 ***
longitude:neighbourhood_groupStaten Island 4.219e+00 7.533e-01 5.601 2.15e-08 ***
longitude:neighbourhood_groupBronx 3.233e+00 4.874e-01 6.633 3.32e-11 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4562 on 38824 degrees of freedom
Multiple R-squared: 0.5246, Adjusted R-squared: 0.5244
F-statistic: 3570 on 12 and 38824 DF, p-value: < 2.2e-16
Model Summary:
All explanatory variables are statistically significant
R-squared: model explains 52.5% of variance in price
- model suffices as an ok explanation
Room_type had the greatest influence on the model
- interpret the coefficient for room_type- entire/apt:
- An increase in entire/apt by one unit (zero to one) is associated
with a change in price by (e^0.73-1) * 100 = 107.5%,
holding all other factors constant
Variable relative importance
# function to calculate variable importance
calc.relimp(model_5, type = "lmg", rela = TRUE)
Response variable: log_price
Total response variance: 0.4375758
Analysis based on 38837 observations
12 Regressors:
Some regressors combined in groups:
Group neighbourhood_group : neighbourhood_groupManhattan neighbourhood_groupQueens neighbourhood_groupStaten Island neighbourhood_groupBronx
Group room_type : room_typeEntire home/apt room_typeShared room
Group longitude:neighbourhood_group : longitude:neighbourhood_groupManhattan longitude:neighbourhood_groupQueens longitude:neighbourhood_groupStaten Island longitude:neighbourhood_groupBronx
Relative importance of 5 (groups of) regressors assessed:
neighbourhood_group room_type longitude:neighbourhood_group longitude availability_365
Proportion of variance explained by model: 52.46%
Metrics are normalized to sum to 100% (rela=TRUE).
Relative importance metrics:
lmg
neighbourhood_group 0.15650767
room_type 0.66297003
longitude:neighbourhood_group 0.03891208
longitude 0.11782702
availability_365 0.02378320
Average coefficients for different model sizes:
1group 2groups 3groups 4groups 5groups
longitude -4.6049149739 -4.1229356833 -4.051358e+00 -3.897941e+00 -3.271661e+00
neighbourhood_groupManhattan 0.3819453426 0.3211757943 -1.070997e+02 -2.511174e+02 -3.218665e+02
neighbourhood_groupQueens -0.2087349654 -0.0655638368 8.477795e+01 1.718999e+02 1.760652e+02
neighbourhood_groupStaten Island -0.2501789720 -0.4947127336 9.315515e+01 2.287431e+02 3.118768e+02
neighbourhood_groupBronx -0.3667919672 -0.2372578195 1.284316e+02 2.514425e+02 2.387853e+02
room_typeEntire home/apt 0.8196414599 0.7858184226 7.602355e-01 7.344142e-01 7.254613e-01
room_typeShared room -0.3741098014 -0.3871140671 -4.059261e-01 -4.118401e-01 -4.263369e-01
availability_365 0.0003947914 0.0005442186 6.232164e-04 6.210777e-04 6.323326e-04
longitude:neighbourhood_groupManhattan NaN NaN -5.805751e+00 -5.096923e+00 -4.354219e+00
longitude:neighbourhood_groupQueens NaN NaN 4.586125e+00 3.487592e+00 2.381855e+00
longitude:neighbourhood_groupStaten Island NaN NaN 5.069942e+00 4.647986e+00 4.219434e+00
longitude:neighbourhood_groupBronx NaN NaN 6.959079e+00 5.105896e+00 3.232856e+00
Variables of relative importance:
Room type, perhaps unsurprisingly, is the most relevant variable for
explaining variations in price. The least explanatory is
availability_365
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShnZ2ZvcnRpZnkpCmxpYnJhcnkobW9kZWxyKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHJlbGFpbXBvKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KFNub3diYWxsQykKbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCgojIEludHJvZHVjdGlvbgoKIyMgQWJvdXQgdGhlIERhdGEKClRoZSBkYXRhIGlzIGFib3V0IE5ldyBZb3JrIENpdHkgQWlyYm5iIGxpc3RpbmdzIGluIDIwMTkuIAoKVGhlIGRhdGEgaW5jbHVkZXMgaW5mb3JtYXRpb24gb24sIHByaWNlcywgTmV3IFlvcmsgbmVpZ2hib3VyaG9vZHMgYW5kIHJvb20gdHlwZXMsCnRvIG5hbWUgYSBmZXcuIEdlb3NwYXRpYWwgY29vcmRpbmF0ZXMgYXJlIGFsc28gcHJlc2VudCwgb2ZmZXJpbmcgdmFsdWFibGUgaW5zaWdodAppbnRvIEFpcmJuYiBsb2NhdGlvbnMuIAoKIyMgUHJvamVjdCBPYmplY3RpdmVzCgpQcmltYXJ5IGFpbToKLSBBbmFseXNlIHRoZSBkZXRlcm1pbmFudHMgb2YgYWlyYm5iIHByaWNlcwogIC0gT2ZmZXIgcmVjb21tZW5kYXRpb25zIGZvciBjdXN0b21lcnMgYm9va2luZyBhaXJibmJzCiAgLSBQcm92aWRlIGluc2lnaHRzIGZvciBob3N0cyAtIGFkb3B0IGFuIGFwcHJvcHJpYXRlIHByaWNpbmcgc3RyYXRlZ3kKICAKIyMgT3ZlcnZpZXcKCi0gRXRoaWNhbCBDb25zaWRlcmF0aW9ucwotIERhdGEgQ2xlYW5pbmcgYW5kIFdyYW5nbGluZwotIEV4cGxvcmF0b3J5IEFuYWx5c2lzCi0gVGV4dCBtaW5pbmcKLSBHZW8tc3BhdGlhbCBBbmFseXNpcwotIE1vZGVsIEJ1aWxkaW5nCiAgLSBVbml2YXJpYXRlIFJlZ3Jlc3Npb24KICAtIE11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uCi0gQW5hbHlzaXMgQ29uY2x1c2lvbnMKCgpgYGB7cn0KcHJpY2VzIDwtIHJlYWRfY3N2KCJyYXdfZGF0YS9BQl9OWUNfMjAxOS5jc3YiKSAlPiUgY2xlYW5fbmFtZXMoKQpgYGAKCgojIEV0aGljYWwgQ29uc2lkZXJhdGlvbnMKClRoZSBkYXRhIGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIGhvc3QgbmFtZXMgYW5kIHVuaXF1ZSBJRHMuIFRvIGF2b2lkIGFueSBldGhpY2FsCmlzc3VlcyBJIGNob3NlIHRvIHJlbW92ZSB0aGVzZSB2YXJpYWJsZXMuIAoKLSBSZWR1Y2UgYmlhcwotIEZvbGxvdyBsYXcgCi0gZW5zdXJlIGNvbnN1bWVyIHRydXN0CgojIENsZWFuIERhdGEKCiMjIENoZWNrIE1pc3NpbmcgVmFsdWVzCgpgYGB7cn0KIyBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMKcHJpY2VzICU+JSAKICAjIHJldHVybiB0b3RhbCBtaXNzaW5nIHZhbHVlcyBpbiBlYWNoIGNvbHVtbgogIHN1bW1hcmlzZSgKICAgIGFjcm9zcygKICAgICAgLmNvbHMgPSBldmVyeXRoaW5nKCksCiAgICAgIC5mbnMgPSB+c3VtKGlzLm5hKC54KSkKICAgICkKICApICU+JSAKICAjIHNlbGVjdCBjb2x1bW5zIHRoYXQgaGF2ZSBtaXNzaW5nIHZhbHVlcwogIGRwbHlyOjpzZWxlY3QoYyhuYW1lLCBob3N0X25hbWUsIGxhc3RfcmV2aWV3LCByZXZpZXdzX3Blcl9tb250aCkpCmBgYApNYW55IG1pc3NpbmcgdmFsdWVzIGluIGxhc3RfcmV2aWV3IGFuZCByZXZpZXdzX3Blcl9tb250aCAoMTAwNTIgcm93cykKCi0gbGFzdF9yZXZpZXcgd2lsbCBiZSBkcm9wcGVkIGFzIGluY29uc2VxdWVudGlhbCB2YXJpYWJsZQotIHZhbHVlcyBkcm9wcGVkIGZyb20gcmV2aWV3c19wZXJfbW9udGgKICAtIGNvYWxlc2Npbmcgd2l0aCBtZWFuIG1heSB3YXJwIGRhdGEgdG9vIG11Y2ggCgoKIyMgRGF0YSBDbGVhbmluZwoKYGBge3J9CnByaWNlc19kZiA8LSBwcmljZXMgJT4lIAogICMgZHJvcCBob3N0IG5hbWVzIGFuZCBob3N0X2lkIChldGhpY2FsKQogIGRwbHlyOjpzZWxlY3QoLWMoaG9zdF9uYW1lLCBob3N0X2lkLCBpZCkpICU+JSAKICAjIHRha2Ugb3V0IG1vbnRoIGZyb20gbGFzdF9yZXZpZXcgCiAgbXV0YXRlKGxhc3RfcmV2aWV3X21vbnRoID0gbW9udGgobGFzdF9yZXZpZXcsIGxhYmVsID0gVFJVRSksCiAgICAgICAgICMgdGFrZSBuYW1lIGxlbmd0aAogICAgICAgICBuYW1lX2xlbmd0aCA9IHN0cl9sZW5ndGgobmFtZSksCiAgICAgICAgICMgaW1wdXRlIG1pc3NpbmcgdmFsdWVzIHdpdGggYXZlcmFnZQogICAgICAgICByZXZpZXdzX3Blcl9tb250aCA9IGNvYWxlc2NlKHJldmlld3NfcGVyX21vbnRoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuKHJldmlld3NfcGVyX21vbnRoLCBuYS5ybSA9IFRSVUUpKQogICAgICAgICApICU+JSAKICAjIHJlbW92ZSBsYXN0X3JldmlldyBjb2x1bW4KICBkcGx5cjo6c2VsZWN0KC1sYXN0X3JldmlldykKCiMgY2hlY2sgZm9yIG1pc3NpbmcgdmFsdWVzCnByaWNlc19kZiAlPiUgCiAgIyByZXR1cm4gdG90YWwgbWlzc2luZyB2YWx1ZXMgaW4gZWFjaCBjb2x1bW4KICBzdW1tYXJpc2UoCiAgICBhY3Jvc3MoCiAgICAgIC5jb2xzID0gZXZlcnl0aGluZygpLAogICAgICAuZm5zID0gfnN1bShpcy5uYSgueCkpCiAgICApCiAgKSAlPiUgCiAgIyBjb2x1bW5zIHRoYXQgcmV0dXJuZWQgbWlzc2luZyB2YWx1ZXMKICBkcGx5cjo6c2VsZWN0KGMobmFtZSwgbGFzdF9yZXZpZXdfbW9udGgsIG5hbWVfbGVuZ3RoKSkKCgojIGRyb3AgbWlzc2luZyB2YWx1ZXMKcHJpY2VzX2RmIDwtIHByaWNlc19kZiAlPiUgCiAgZHJvcF9uYSgpCgoKCmBgYAoKCiMgRXhwbG9yYXRvcnkgQW5hbHlzaXMKCiMjIFRvdGFsIE51bWJlciBvZiBCb29raW5ncyBwZXIgQm9yb3VnaAoKYGBge3J9CiMgbnVtYmVyIG9mIGJvb2tpbmdzIHBlciBib3JvdWdoCnByaWNlc19kZiAlPiUgCiAgIyBncm91cCBieSBuZWlnaGJvdXJob29kCiAgZ3JvdXBfYnkobmVpZ2hib3VyaG9vZF9ncm91cCkgJT4lIAogICMgcmV0dXJuIHRvdGFsIGJvb2tpbmdzIGZvciBlYWNoIG5laWdoYm91cmhvb2QKICBzdW1tYXJpc2UobnVtX2Jvb2tpbmdzID0gbigpKSAlPiUgCiAgIyBhcnJhbmdlIGZyb20gaGlnaGVzdCB0byBsb3dlc3QKICBhcnJhbmdlKGRlc2MobnVtX2Jvb2tpbmdzKSkgJT4lIAogICMgY3JlYXRlIGEgYmFyIGNoYXJ0IHRvIHZpc3VhbGlzZSByZXN1bHQgCiAgZ2dwbG90KGFlcyhyZW9yZGVyKG5laWdoYm91cmhvb2RfZ3JvdXAsIG51bV9ib29raW5ncyksIG51bV9ib29raW5ncywgCiAgICAgICAgICAgICBmaWxsID0gbmVpZ2hib3VyaG9vZF9ncm91cCkpICsKICAjIHNwZWNpZnkgYmFyIGNoYXJ0CiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICMgYW5ub3RhdGUgZWFjaCBiYXIKICBnZW9tX2xhYmVsKG1hcHBpbmcgPSBhZXMobGFiZWwgPSBudW1fYm9va2luZ3MpLCBzaXplID0gMywgCiAgICAgICAgICAgICBmaWxsID0gIiNGNUZGRkEiLCBmb250ZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpICsKICAjIGFkZCB0aGVtZQogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyB0aXRsZXMKICBsYWJzKHggPSAiQm9yb3VnaCIsIHkgPSAiTnVtYmVyIG9mIEJvb2tpbmdzIiwgCiAgICAgICB0aXRsZSA9ICJUb3RhbCBOdW1iZXIgb2YgQm9va2luZ3MgcGVyIEJvcm91Z2giKQpgYGAKTWFuaGF0dGFuIGFuZCBCcm9va2x5biBib3RoIGJ5IGZhciB0aGUgbW9zdCBwb3B1bGFyIGFyZWFzIGZvciBBaXJibmIgbGlzdGluZ3MuCgpUd28gY2VudHJhbCBCb3JvdWdocyB3aGljaCBtYXkgaW5kaWNhdGUgdGhlIG1haW4gcmVhc29uIHBlb3BsZSBib29rIGlzIGZvciAKaG9saWRheXMgLyBUb3VyaXNtLiAKCgojIyBBdmVyYWdlIFByaWNlIHBlciBOZWlnaGJvdXJob29kIEdyb3VwCgpgYGB7cn0KCiMgQXZlcmFnZSBQcmljZSBwZXIgUm9vbQpwcmljZV9wZXJfcm9vbSA8LSBwcmljZXNfZGYgJT4lIAogICMgZ3JvdXAgYnkgcm9vbV90eXBlCiAgZ3JvdXBfYnkocm9vbV90eXBlKSAlPiUgCiAgIyByZXR1cm4gYXZlcmFnZSBwcmljZSBwZXIgcm9vbV90eXBlCiAgc3VtbWFyaXNlKGF2Z19wcmljZSA9IG1lYW4ocHJpY2UpKSAlPiUgCiAgIyBjcmVhdGUgYmFyIGNoYXJ0IHRvIHZpc3VhbGlzZSByZXN1bHQKICBnZ3Bsb3QoYWVzKHJvb21fdHlwZSwgYXZnX3ByaWNlLCBmaWxsID0gcm9vbV90eXBlKSkgKwogICMgc3BlY2lmeSBiYXIgY2hhcnQKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgIyBhbm5vdGF0ZSBlYWNoIGJhcgogIGdlb21fbGFiZWwobWFwcGluZyA9IGFlcyhsYWJlbCA9IHJvdW5kKGF2Z19wcmljZSwgMikpLCBzaXplID0gNiwgCiAgICAgICAgICAgICBmaWxsID0gIiNGNUZGRkEiLCBmb250ZmFjZSA9ICJib2xkIiwgCiAgICAgICAgICAgICAjIHBvc2l0aW9uIGNoYW5nZSB0byBtYWtlIHN1cmUgbGFiZWwgc3RheXMgb24gcGFnZQogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuOSkpICsKICAjIGFkZCB0aGVtZQogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyB0aXRsZXMKICBsYWJzKHggPSAiUm9vbSBUeXBlIiwgeSA9ICJBdmVyYWdlIFByaWNlICgkKSIsIAogICAgICAgdGl0bGUgPSAiQXZlcmFnZSBQcmljZSBieSBSb29tIFR5cGUiKQoKCiMgQXZlcmFnZSBwcmljZSBwZXIgbmVpZ2hib3VyaG9vZCBncm91cApwcmljZV9yb29tX2Jvcm91Z2ggPC0gcHJpY2VzX2RmICU+JSAKICAjIGdyb3VwIGJ5IGJvdGggbmVpZ2hib3VyaG9vZCBhbmQgcm9vbV90eXBlCiAgZ3JvdXBfYnkobmVpZ2hib3VyaG9vZF9ncm91cCwgcm9vbV90eXBlKSAlPiUgCiAgIyByZXR1cm4gYXZlcmFnZSBwcmljZSBmb3IgZWFjaCByb29tIHR5cGUgaW4gZWFjaCBuZWlnaGJvdXJob29kCiAgc3VtbWFyaXNlKGF2Z19wcmljZSA9IG1lYW4ocHJpY2UpKSAlPiUgCiAgIyBzb3J0IGZyb20gaGlnaGVzdCB0byBsb3dlc3QgcHJpY2UKICBhcnJhbmdlKGRlc2MoYXZnX3ByaWNlKSkgJT4lIAogICMgY3JlYXRlIGJhciBjaGFydAogIGdncGxvdChhZXMocmVvcmRlcihuZWlnaGJvdXJob29kX2dyb3VwLCBhdmdfcHJpY2UpLCBhdmdfcHJpY2UsIAogICAgICAgICAgICAgZmlsbCA9IHJvb21fdHlwZSkpICsKICAjIHNwZWNpZnkgYmFyIGNoYXJ0CiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyAKICAjIGFubm90YXRlIGJhcnMKICBnZW9tX2xhYmVsKG1hcHBpbmcgPSBhZXMobGFiZWwgPSByb3VuZChhdmdfcHJpY2UsIDIpKSwgc2l6ZSA9IDIuNSwgCiAgICAgICAgICAgICBmaWxsID0gIiNGNUZGRkEiLCBmb250ZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUsIAogICAgICAgICAgICAgIyBwb3NpdGlvbiBjaGFuZ2UgdG8gbWFrZSBzdXJlIGxhYmVsIHN0YXlzIG9uIHBhZ2UKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjkpKSArCiAgIyB0aGVtZQogIHRoZW1lX2NsYXNzaWMoKSArCiAgIyB0aXRsZXMKICBsYWJzKHggPSAiTmV3IFlvcmsgQm9yb3VnaHMiLCB5ID0gIkF2ZXJhZ2UgUHJpY2UgKCQpIiwgCiAgICAgICB0aXRsZSA9ICJBdmVyYWdlIFByaWNlIHBlciBCb3JvdWdoIGJ5IFJvb20gVHlwZSIpICsgCiAgIyBzcGxpdCBpbnRvIHJvb21fdHlwZXMKICBmYWNldF93cmFwKH5yb29tX3R5cGUpICsKICAjIGZsaXAgeCBhbmQgeSBheGlzCiAgY29vcmRfZmxpcCgpCgojIHBsb3QgYm90aCB2aXN1YWxpc2F0aW9ucyB0b2dldGhlcgpjb3dwbG90OjpwbG90X2dyaWQocHJpY2VfcGVyX3Jvb20sIHByaWNlX3Jvb21fYm9yb3VnaCwgbnJvdyA9IDIpCmBgYAoKCiMjIFRoZSAxMCBtb3N0IGV4cGVuc2l2ZSBhbmQgY2hlYXBlc3QgTmV3IFlvcmsgRGlzdHJpY3RzCgpgYGB7cn0KIyBUb3AgMTAgbW9zdCBleHBlbnNpdmUgZGlzdHJpY3RzIG9uIGF2ZXJhZ2UKYSA8LSBwcmljZXNfZGYgJT4lIAogICMgZ3JvdXAgYnkgaW5kaXZpZHVhbCBkaXN0cmljdHMgd2l0aGluIG5laWdoYm91cmhvb2RzCiAgZ3JvdXBfYnkobmVpZ2hib3VyaG9vZCkgJT4lIAogICMgcmV0dXJuIGF2ZXJhZ2UgcHJpY2UKICBzdW1tYXJpc2UoYXZnX3ByaWNlID0gbWVhbihwcmljZSkpICU+JSAKICAjIHNvcnQgZnJvbSBoaWdoZXN0IHRvIGxvd2VzdAogIGFycmFuZ2UoZGVzYyhhdmdfcHJpY2UpKSAlPiUgCiAgIyByZXR1cm4gdGhlIHRvcCAxMCAob3V0IG9mIDIxOCkKICBzbGljZSgxOjEwKSAlPiUgCiAgIyBjcmVhdGUgYmFyIHBsb3QKICBnZ3Bsb3QoYWVzKHJlb3JkZXIobmVpZ2hib3VyaG9vZCwgYXZnX3ByaWNlKSwgYXZnX3ByaWNlLCAKICAgICAgICAgICAgIGZpbGwgPSBuZWlnaGJvdXJob29kKSkgKyAKICAjIHNwZWNpZnkgYmFyIGNoYXJ0CiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICMgYW5ub3RhdGUgYmFycyAKICBnZW9tX2xhYmVsKG1hcHBpbmcgPSBhZXMobGFiZWwgPSByb3VuZChhdmdfcHJpY2UsIDIpKSwgc2l6ZSA9IDMsIAogICAgICAgICAgICAgZmlsbCA9ICIjRjVGRkZBIiwgZm9udGZhY2UgPSAiYm9sZCIpICsKICAjIHRoZW1lCiAgdGhlbWVfY2xhc3NpYygpICsKICAjIGNoYW5nZSB4LWF4aXMgbGFiZWwgcG9zaXRpb24KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCB2anVzdCA9IDAuOTUsIGhqdXN0ID0gMSkpICsKICAjIHRpdGxlcwogIGxhYnMoeCA9ICJOZWlnaGJvdXJob29kIiwgeSA9ICJBdmVyYWdlIFByaWNlICgkKSIsIAogICAgICAgdGl0bGUgPSAiVGhlIDEwIE1vc3QgRXhwZW5zaXZlIERpc3RyaWN0cyBvbiBBdmVyYWdlIikKCiMgdG9wIDEwIGxlYXN0IGV4cGVuc2l2ZSBkaXN0cmljdHMgb24gYXZlcmFnZQpiIDwtIHByaWNlc19kZiAlPiUgCiAgIyBncm91cCBieSBpbmRpdmlkdWFsIGRpc3RyaWN0cyB3aXRoaW4gbmVpZ2hib3VyaG9vZHMKICBncm91cF9ieShuZWlnaGJvdXJob29kKSAlPiUgCiAgIyByZXR1cm4gYXZlcmFnZSBwcmljZXMKICBzdW1tYXJpc2UoYXZnX3ByaWNlID0gbWVhbihwcmljZSkpICU+JSAKICAjIGFycmFuZ2UgZnJvbSBsb3dlc3QgdG8gaGlnaGVzdAogIGFycmFuZ2UoYXZnX3ByaWNlKSAlPiUgCiAgIyByZXR1cm4gYm90dG9tIDEwIHByaWNlcwogIHNsaWNlKDE6MTApICU+JSAKICAjIGNyZWF0ZSBiYXIgY2hhcnQKICBnZ3Bsb3QoYWVzKHJlb3JkZXIobmVpZ2hib3VyaG9vZCwgYXZnX3ByaWNlKSwgYXZnX3ByaWNlLCAKICAgICAgICAgICAgIGZpbGwgPSBuZWlnaGJvdXJob29kKSkgKyAKICAjIHNwZWNpZnkgYmFyIGNoYXJ0CiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICMgYW5ub3RhdGUgYmFycwogIGdlb21fbGFiZWwobWFwcGluZyA9IGFlcyhsYWJlbCA9IHJvdW5kKGF2Z19wcmljZSwgMikpLCBzaXplID0gMywgCiAgICAgICAgICAgICBmaWxsID0gIiNGNUZGRkEiLCBmb250ZmFjZSA9ICJib2xkIikgKwogICMgdGhlbWUKICB0aGVtZV9jbGFzc2ljKCkgKwogICMgY2hhbmdlIHgtYXhpcyBsYWJlbCBwb3NpdGlvbgogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMC45NSwgaGp1c3QgPSAxKSkgKwogICMgdGl0bGVzCiAgbGFicyh4ID0gIk5laWdoYm91cmhvb2QiLCB5ID0gIkF2ZXJhZ2UgUHJpY2UgKCQpIiwgCiAgICAgICB0aXRsZSA9ICJUaGUgMTAgTGVhc3QgRXhwZW5zaXZlIERpc3RyaWN0cyBvbiBBdmVyYWdlIikKCiMgYWRkIHBsb3RzIGludG8gdGhlIHNhbWUgb3V0cHV0CmNvd3Bsb3Q6OnBsb3RfZ3JpZChhLCBiLCBucm93PTIpCmBgYAoKVGhlIDEwIG1vc3QgZXhwZW5zaXZlIGRpc3RyaWN0cyBhcmUgYWxsIGxvY2F0ZWQgaW4gTWFuaGF0dGFuIGFwYXJ0IGZyb20sIApOZXBvbnNpdCAoUXVlZW5zKSBhbmQgV2lsbG93QnJvb2sgKFN0YXRlbiBJc2xhbmQpCgpUaGUgbWFqb3JpdHkgb2YgdGhlIDEwIGxlYXN0IGV4cGVuc2l2ZSBkaXN0cmljdHMgcmVzaWRlIGluIHRoZSBCcm9ueCwgU3RhdGUgCklzbGFuZCBhbmQgUXVlZW5zCgojIyBBdmVyYWdlIFJldmlld3MgYnkgTGFzdCBNb250aCBSZXZpZXcgU3VibWl0dGVkCgpgYGB7cn0KIyBBdmVyYWdlIFJldmlld3MgcGVyIE1vbnRoIGJ5IExhc3QgTW9udGggcmV2aWV3IHdhcyBsZWZ0CnByaWNlc19kZiAlPiUgCiAgIyBjaGFuZ2UgbGFzdF9yZXZpZXdfbW9udGggdG8gYSBmYWN0b3IgCiAgbXV0YXRlKGxhc3RfcmV2aWV3X21vbnRoID0gYXNfZmFjdG9yKGxhc3RfcmV2aWV3X21vbnRoKSkgJT4lIAogICMgZ3JvdXAgYnkgbGFzdF9yZXZpZXdfbW9udGgKICBncm91cF9ieShsYXN0X3Jldmlld19tb250aCkgJT4lIAogICMgcmV0dXJuIHRoZSBhdmVyYWdlX3Jldmlld3NfcGVyX21vbnRoIAogIHN1bW1hcmlzZShuID0gbWVhbihyZXZpZXdzX3Blcl9tb250aCkpICU+JSAKICAjIGNyZWF0ZSBhIGJhciBncmFwaAogIGdncGxvdChhZXMobGFzdF9yZXZpZXdfbW9udGgsIG4sIGZpbGwgPSBsYXN0X3Jldmlld19tb250aCkpICsgCiAgIyBzcGVjaWZ5IGJhciBncmFwaAogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICAjIHRoZW1lCiAgdGhlbWVfYncoKSArCiAgIyB0aXRsZXMKICBsYWJzKHggPSAiTGFzdCBSZXZpZXcgTW9udGgiLCB5ID0gIkF2ZXJhZ2UgUmV2aWV3cyBwZXIgTW9udGgiLCAKICAgICAgIHRpdGxlID0gIkF2ZXJhZ2UgUmV2aWV3cyBieSBMYXN0IE1vbnRoIFJldmlldyBTdWJtaXR0ZWQiKQpgYGAKClN1Z2dlc3RzIHRoYXQgbW9zdCBwZW9wbGUgYXJlIGxlYXZpbmcgcmV2aWV3cyBpbiB0aGUgc3VtbWVyLCBpbmRpY2F0aW5nIHNvbWUKc2Vhc29uYWxpdHkgdG8gQWlyYm5iIGJvb2tpbmcgaW4gTmV3IFlvcmsuIAoKCiMgUHJpY2UgRGVuc2l0eSBieSBBcmVhCgpgYGB7cn0KIyBwcmljZSBkZW5zaXR5IGJ5IE5ldyBZb3JrIEJvcm91Z2gKZ2dwbG90KAogICMgY3JlYXRlIHBsb3QgZm9yIHByaWNlIGxlc3MgdGhhbiAkNTAwCiAgc3Vic2V0KHByaWNlc19kZiwgcHJpY2UgPCA1MDApLGFlcyh4ID0gcHJpY2UpKSArCiAgIyBzcGVjaWZ5IGRlbnNpdHkgcGxvdAogIGdlb21fZGVuc2l0eSgKICAgIG1hcHBpbmcgPSBhZXMoZmlsbCA9IG5laWdoYm91cmhvb2RfZ3JvdXApLCAKICAgIGJhbmR3aWR0aCA9IDEwMCwgYWxwaGEgPSAxLCBzaXplID0gMC41LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgIyB0aGVtZQogIHRoZW1lX2J3KCkgKwogICMgc2hvdyBpbmRpdmlkdWFsIGRlbnNpdHkgcGxvdHMgZm9yIGJvcm91Z2hzCiAgZmFjZXRfd3JhcCh+bmVpZ2hib3VyaG9vZF9ncm91cCkgKwogICMgdGl0bGVzCiAgbGFicyh4ID0gIlByaWNlIiwgeSA9ICJEZW5zaXR5IiwgdGl0bGUgPSAiUHJpY2UgRGVuc2l0eSBieSBCb3JvdWdoIikKYGBgCgpQcmljaW5nIGRlbnNpdHkgcGxvdCByZXZlYWxzIHRoYXQgYm9yb3VnaHMgd2l0aCBmZXdlciBhbW91bnQgb2YgYm9va2luZ3MgKFF1ZWVucywKU3RhdGVuIElzbGFuZCBhbmQgQnJvbngpIGhhdmUgYSBoaWdoZXIgZGVuc2l0eSBvZiBsb3dlciBwcmljZXMgCgpNb3N0IGNvbW1vbiBhcmVhcyAoTWFoYXR0YW4gYW5kIEJyb29rbHluKSBoYXZlIGEgd2lkZXIgZGVuc2l0eSBwbG90IGluZGljYXRpbmcgCnRoYXQgcHJpY2VzIHZhcnkgbW9yZS4gCgoKIyBUZXh0IE1pbmluZwoKSSB3YW50IHRvIGZpbmQgdGhlIHdvcmRzIHRoYXQgYXJlIGFzc29jaWF0ZWQgd2l0aCBkaWZmZXJlbnQgcHJpY2UgcmFuZ2VzLiAKClNvIEkgbmVlZCB0byBjcmVhdGUgbmV3IHZhcmlhYmxlcyB3aGljaCBjbGFzc2lmeSB0aGUgcHJpY2UgcmFuZ2Ugb2YgZWFjaAphaXJibmIKCndlIHdpbGwgZGVmaW5lIHByaWNlIHJhbmdlcyBiYXNlZCBhcm91bmQgdGhlIGF2ZXJhZ2UgcHJpY2UgZm9yIHRvdGFsIGJvb2tpbmdzCgpgYGB7cn0KIyByZXR1cm4gbWVhbl9wcmljZSBvZiBBaXJibmJzCnByaWNlc19kZiAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fcHJpY2UgPSBtZWFuKHByaWNlKSkKYGBgCm1lYW4gcHJpY2UgaXMgJDE0MiB0aGVyZWZvcmUsIGxvdyB3aWxsIGJlIGxlc3MgdGhhbiAkMTAwLCBtZWRpdW0gd2lsbCBiZSAKYmV0d2VlbiAkMTAwIC0gJDIwMCwgaGlnaCB3aWxsIGJlICQyMDAgLSAkMzAwIGFuZCB2ZXJ5IGhpZ2ggd2lsbCBiZSBncmVhdGVyIHRoYW4KJDMwMAoKYGBge3J9CiMgY3JlYXRlIG5ldyBjYXRlZ29yaWNhbCB2YXJpYWJsZSBmb3IgcHJpY2UKcHJpY2VzX25ldyA8LSBwcmljZXNfZGYgJT4lIAogIG11dGF0ZShwcmljZV9jbGFzcyA9IGNhc2Vfd2hlbigKICAgIHByaWNlIDwgMTAwIH4gIkxvdyIsIAogICAgcHJpY2UgPCAyMDAgfiAiTWVkaXVtIiwgCiAgICBwcmljZSA8IDMwMCB+ICJIaWdoIiwKICAgIFRSVUUgfiAiVmVyeSBIaWdoIgogICkpCiAgCmBgYAoKCgojIyBIaWdoL1ZlcnkgSGlnaCBQcmljZSBSYW5nZQoKCmBgYHtyfQojIHdvcmRzIGFzc29jaWF0ZWQgd2l0aCBoaWdoIHByaWNlcwpoaWdoX3ByaWNlX3dvcmRzIDwtIHByaWNlc19uZXcgJT4lIAogICMgZmlsdGVyIGZvciBIaWdoIGFuZCBWZXJ5IEhpZ2ggcHJpY2UgY2xhc3NlcyAKICBmaWx0ZXIocHJpY2VfY2xhc3MgJWluJSBjKCJIaWdoIiwgIlZlcnkgSGlnaCIpKSAlPiUgCiAgIyB0YWtlIGluZGl2aWR1YWwgd29yZHMgZnJvbSB0aGUgbmFtZSBjb2x1bW4KICB1bm5lc3RfdG9rZW5zKHdvcmQsIG5hbWUpICU+JSAKICAjIHRha2Ugb3V0IHN0b3Bfd29yZHMgCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JSAKICAjIHNlbGVjdCB3b3JkIGNvbHVtbgogIGRwbHlyOjpzZWxlY3Qod29yZCkKCiMgbW9zdCBjb21tb24gd29yZHMKc29ydGVkX2hwX3dvcmRzIDwtIGhpZ2hfcHJpY2Vfd29yZHMgJT4lCiAgIyBzb3J0IG1vc3QgY29tbW9uIHdvcmRzCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpCgojIGNyZWF0ZSB3b3JkIGNsb3VkIGZvciBoaWdoL3ZlcnkgaGlnaCBwcmljZSBBaXJibmJzCndvcmRjbG91ZCgKICAjIHdvcmRzIHRvIHVzZSBmb3Igd29yZCBjbG91ZCAKICB3b3JkcyA9IHNvcnRlZF9ocF93b3JkcyR3b3JkLAogICMgbnVtYmVyIG9mIHRpbWVzIHRoZXNlIHdvcmRzIGFwcGVhcgogIGZyZXEgPSBzb3J0ZWRfaHBfd29yZHMkbiwgCiAgIyBtYXhpbXVtIG51bWJlciBvZiB3b3JkcyB1c2VkCiAgbWF4LndvcmRzPTYwLCAKICAjIG5vIHJhbmRvbSBvcmRlcgogIHJhbmRvbS5vcmRlcj1GQUxTRSwgCiAgIyBwcm9wb3J0aW9uIG9mIHdvcmRzIHdpdGggYSA5MCBkZWdyZWUgYW5nbGUKICByb3QucGVyPTAuMzUsIAogICMgYWRkIGNvbG91ciBwYWxldHRlCiAgY29sb3JzPWJyZXdlci5wYWwoOCwgIlNwZWN0cmFsIikpCgpgYGAKCgpXb3JkcyB0aGF0IHN0YW5kIG91dCBmcm9tIHdvcmRjbG91ZCBpbmNsdWRlOiBiZWRyb29tLCBhcGFydG1lbnQsIHZpbGxhZ2UsIGx1eHVyeSwgCmxvY2F0aW9uLCBNYW5oYXR0YW4sIHNwYWNpb3VzLCBwYXJrCi0gc3RhcnQgdG8gdW5kZXJzdGFuZCB3aGF0IGtpbmQgb2YgQWlyYm5icyBhcmUgYmVpbmcgYWR2ZXJ0aXNlZCBmb3IgaGlnaCBwcmljZXMKCgojIyBMb3cgUHJpY2UgUmFuZ2UKCgpgYGB7cn0KIyB3b3JkcyBhc3NvY2lhdGVkIHdpdGggbG93IHByaWNlcwpsb3dfcHJpY2Vfd29yZHMgPC0gcHJpY2VzX25ldyAlPiUgCiAgIyBmaWx0ZXIgZm9yIHJvd3MgYXNzb2NpYXRlZCB3aXRoIGxvdyBwcmljZXMKICBmaWx0ZXIocHJpY2VfY2xhc3MgJWluJSAiTG93IikgJT4lIAogICMgdGFrZSB3b3JkcyBmcm9tIG5hbWUgY29sdW1uCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCBuYW1lKSAlPiUgCiAgIyByZW1vdmUgc3RvcCB3b3JkcwogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUgCiAgIyBzZWxlY3Qgd29yZCBjb2x1bW4KICBkcGx5cjo6c2VsZWN0KHdvcmQpCgojIG1vc3QgY29tbW9uIHdvcmRzCnNvcnRlZF9scF93b3JkcyA8LSBsb3dfcHJpY2Vfd29yZHMgJT4lIAogICMgc29ydCBtb3N0IGNvbW1vbiB3b3JkcwogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQoKd29yZGNsb3VkKAogICMgc2VsZWN0IHdvcmRzIAogIHdvcmRzID0gc29ydGVkX2xwX3dvcmRzJHdvcmQsIAogICMgbnVtYmVyIG9mIHRpbWVzIHRoZXNlIHdvcmRzIGFwcGVhcgogIGZyZXEgPSBzb3J0ZWRfbHBfd29yZHMkbiwgCiAgIyBtYXhpbXVtIG51bWJlciBvZiB3b3JkcyBpbiBjbG91ZAogIG1heC53b3Jkcz02MCwgCiAgIyBubyByYW5kb20gb3JkZXIKICByYW5kb20ub3JkZXI9RkFMU0UsIAogICMgcHJvcG9ydGlvbiBvZiB3b3JkcyByb3RhdGVkCiAgcm90LnBlcj0wLjM1LCAKICAjIGNvbG91ciBwYWxldHRlCiAgY29sb3JzPWJyZXdlci5wYWwoOCwgIlNwZWN0cmFsIikpCmBgYAoKd2hlbiB3ZSBsb29rIGF0IHRoZSB3b3JkIGNsb3VkIG9mIHRoZSBsb3cgcHJpY2UgcmFuZ2UsIHdlIHNlZSBzb21lIHNpbWlsYXJpdGllcwp3aXRoIHRoZSBoaWdoIHByaWNlIHJhbmdlIGluZGljYXRpbmcgb3duZXJzIGFyZSB0cnlpbmcgdG8gc2VsbCB0aGUgcHJvcGVydHkgYXMKdXAgbWFya2V0LiAKCkJpZyBlbXBoYXNpcyBvbiBwcm9wZXJ0eSBiZWluZyAicHJpdmF0ZSIgd2hpY2ggaXMgbGlrZWx5IHRvIGJlIGEgYmlnIGNvbmNlcm4KZm9yIHBlb3BsZSB3aGVuIG5vdCBwYXlpbmcgdGhhdCBtdWNoLiBJbiBjb250cmFzdCwgcHJpdmFjeSBpcyBhIGdpdmVuIHdoZW4gcGF5aW5nCmZvciBoaWdoIGVuZCBhY2NvbW1vZGF0aW9uLiAKCgoKIyMgTWVkaXVtIFByaWNlIFJhbmdlCgpgYGB7cn0KIyB3b3JkcyBhc3NvY2lhdGVkIHdpdGggbWVkaXVtIHByaWNlIHJhbmdlIChhcm91bmQgdGhlIGF2ZXJhZ2UpCm1lZGl1bV9wcmljZV93b3JkcyA8LSBwcmljZXNfbmV3ICU+JSAKICAjIGZpbHRlciByb3dzIGFzc29jaWF0ZWQgd2l0aCBtZWRpdW0gcHJpY2UgcmFuZ2UKICBmaWx0ZXIocHJpY2VfY2xhc3MgJWluJSAiTWVkaXVtIikgJT4lIAogICMgc2VsZWN0IHdvcmRzIGZyb20gbmFtZSBjb2x1bW4KICB1bm5lc3RfdG9rZW5zKHdvcmQsIG5hbWUpICU+JSAKICAjIHJlbW92ZSBzdG9wIHdvcmRzCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JSAKICAjIHNlbGVjdCB3b3JkcwogIGRwbHlyOjpzZWxlY3Qod29yZCkKCgojIG1vc3QgY29tbW9uIHdvcmRzCnNvcnRlZF9tcF93b3JkcyA8LSBtZWRpdW1fcHJpY2Vfd29yZHMgJT4lIAogICMgc29ydCB3b3JkcwogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQoKCiMgd29yZCBjbG91ZCBmb3IgbWVkaXVtIHByaWNlIHJhbmdlCndvcmRjbG91ZCgKICAjIHdvcmRzIHRvIHVzZQogIHdvcmRzID0gc29ydGVkX21wX3dvcmRzJHdvcmQsIAogICMgZnJlcXVlbmN5IHdvcmRzIGFwcGVhcgogIGZyZXEgPSBzb3J0ZWRfbXBfd29yZHMkbiwgCiAgIyBtYXhpbXVtIG51bWJlciBvZiB3b3JkcwogIG1heC53b3Jkcz02MCwgCiAgIyByYW5kb20gb3JkZXIgPSBGQUxTRSAtLT4gbWFrZXMgaXQgbmVhdAogIHJhbmRvbS5vcmRlcj1GQUxTRSwgCiAgIyBwcm9wb3J0aW9uIG9mIHdvcmRzIHJvdGF0ZWQKICByb3QucGVyPTAuMzUsIAogICMgY29sb3VyIHBhbGV0dGUKICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiU3BlY3RyYWwiKSkKYGBgCgpOb3QgYSB0cmVtZW5kb3VzIGFtb3VudCBvZiBkaWZmZXJlbmNlIGhlcmUsIHByb2JhYmx5IGFzIGV4cGVjdGVkIGl0IHRha2VzIGEgCmJhbGFuY2UgYmV0d2VlbiBsb3cgYW5kIGhpZ2ggcHJpY2UgcmFuZ2VzIGhpZ2hsaWdodGluZyBwcml2YWN5IGFzIGltcG9ydGFudCBidXQgCmFsc28gbW9yZSBlbXBoYXNpcyBvbiBsb2NhdGlvbi4gCgoKIyBNb3N0IFBvcHVsYXIgQmlncmFtcyB1c2VkIGluIEFpcmJuYiBOYW1lCgpBbmFseXNpcyBvZiB0aGUgbW9zdCBwb3B1bGFyIHdvcmQgY29tYmluYXRpb25zCgpgYGB7cn0KIyBPYnRhaW4gdGhlIDIgd29yZCBiaWdyYW1zCmJpZ3JhbV9uYW1lcyA8LSBwcmljZXNfbmV3ICU+JSAKICB1bm5lc3RfdG9rZW5zKGJpZ3JhbSwgbmFtZSwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpCgojIFNlcGFyYXRlIGludG8gdHdvIHdvcmRzCmJpZ3JhbXNfc2VwYXJhdGVkIDwtIGJpZ3JhbV9uYW1lcyAlPiUgCiAgc2VwYXJhdGUoYmlncmFtLCBjKCJ3b3JkMSIsICJ3b3JkMiIpLCBzZXAgPSAiICIpCgojIGZpbHRlciB0aGUgd29yZHMgZm9yIHN0b3Agd29yZHMKYmlncmFtc19maWx0ZXJlZCA8LSBiaWdyYW1zX3NlcGFyYXRlZCAlPiUgCiAgIyBmaWx0ZXIgd29yZHMgTk9UIElOIHN0b3Agd29yZHMKICBmaWx0ZXIoIXdvcmQxICVpbiUgc3RvcF93b3JkcyR3b3JkKSAlPiUgCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHN0b3Bfd29yZHMkd29yZCkKCiMgY291bnQgYW5kIHNvcnQgdGhlIG1vc3QgcG9wdWxhciB3b3JkcwpiaWdyYW1zX2NvdW50cyA8LSBiaWdyYW1zX2ZpbHRlcmVkICU+JSAKICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKQoKIyBtb3N0IHBvcHVsYXIgYmlncmFtcyBncmFwaApiaWdyYW1zX2NvdW50cyAlPiUgCiAgIyBmaWx0ZXIgb3V0IG51bWJlcnMKICBmaWx0ZXIoIXN0cl9kZXRlY3Qod29yZDEsICJbMC05XSIpKSAlPiUgCiAgIyB1bml0ZSBib3RoIHdvcmQgY29sdW1ucwogIHVuaXRlKGNvbCA9ICJiaWdyYW1zIiwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiLCByZW1vdmUgPSBUUlVFKSAlPiUgCiAgIyBnZXQgdG9wIDEwCiAgc2xpY2UoMToxMCkgJT4lIAogICMgdmlzdWFsaXNlCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGJpZ3JhbXMsIG4pLCBuLCBmaWxsID0gYmlncmFtcykpICsgCiAgIyBzcGVjaWZ5IGJhciBncmFwaAogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICAjIGZsaXAgeCBhbmQgeS1heGlzCiAgY29vcmRfZmxpcCgpICsKICAjIHRoZW1lCiAgdGhlbWVfYncoKSArIAogICMgYW5ub3RhdGUgZWFjaCBiYXIKICBnZW9tX2xhYmVsKG1hcHBpbmcgPSBhZXMobGFiZWwgPSBuKSwgc2l6ZSA9IDMsIAogICAgICAgICAgICAgZmlsbCA9ICIjRjVGRkZBIiwgZm9udGZhY2UgPSAiYm9sZCIpICsKICAjIHRpdGxlcwogIGxhYnMoeSA9ICJOdW1iZXIgb2YgQmlncmFtIE1lbnRpb25zIiwgeCA9ICJCaWdyYW0iLCAKICAgICAgIHRpdGxlID0gIk1vc3QgUG9wdWxhciBCaWdyYW1zIGluIEFpcmJuYiBOYW1lIikKCmBgYAoKSG9zdHMgZW1waGFzaXMgb24gbG9jYXRpb24gaXMgYSBjb21tb24gc3RyYXRlZ3kgdG8gZW50aWNlIGNvbnN1bWVycwoKY29uc3VtZXJzIHdhbnQgdG8gYmUgY2xvc2VyIHRvIGZhbW91cyBsYW5kbWFya3MuIAoKCiMgR2VvLXNwYXRpYWwgQW5hbHlzaXMKCgpDYW4gd2Ugc2VlIGlmIHRoZSBnZW8tc3BhdGlhbCBiYWNrcyB1cCB0aGUgd29yZCBjbG91ZCBhbmQgYmlncmFtIGFuYWx5c2lzIG9mIAplbXBoYXNpcyBvbiBsb2NhdGlvbiBmb3IgbWVkaXVtIGFuZCBsb3cgcHJpY2UgcmFuZ2VzCgojIyBEZW5zaXR5IG9mIE5ldyBZb3JrIEJvcm91Z2hzCgoKYGBge3J9CiMgRGVuc2l0eSBvZiBOZXcgWW9yayBCb3JvdWdocwpwcmljZXNfbmV3ICU+JSAKICAjIHBsb3QgbG9uZ2l0dWRlIGFuZCBsYXRpdHVkZQogIGdncGxvdChhZXMobG9uZ2l0dWRlLCBsYXRpdHVkZSkpICsKICAjIHNwZWNpZnkgZGVuc2l0eSBwbG90IC0gaGFzIHRvIGJlIGdlb21fZGVuc2l0eTJkCiAgIyBzcGVjaWZ5IGRlbnNpdHkgYnkgbmVpZ2hib3VyaG9vZHMKICBnZW9tX2RlbnNpdHkyZChhZXMoY29sb3VyID0gbmVpZ2hib3VyaG9vZF9ncm91cCkpICsgCiAgIyB0aGVtZQogIHRoZW1lX2J3KCkgKwogICMgdGl0bGUKICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgb2YgQm9yb3VnaHMiKQpgYGAKCiMjIERlbnNpdHkgb2YgUHJpY2UgQ2xhc3MKCmBgYHtyfQojIERlbnNpdHkgb2YgUHJpY2UgQ2xhc3MKcHJpY2VzX25ldyAlPiUgCiAgIyBwbG90IGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUKICBnZ3Bsb3QoYWVzKGxvbmdpdHVkZSwgbGF0aXR1ZGUpKSArCiAgIyBzcGVjaWZ5IGRlbnNpdHkgYnkgcHJpY2VfY2xhc3MKICBnZW9tX2RlbnNpdHkyZChhZXMoY29sb3VyID0gcHJpY2VfY2xhc3MpKSArIAogICMgdGhlbWUKICB0aGVtZV9idygpICsKICAjIHRpdGxlcwogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBvZiBQcmljZSBDbGFzcyIpCgpgYGAKCgpjYW4gc2VlIHRoZSBzcHJlYWQgb2YgcHJpY2VzIGJhc2VkIG9uIHRoZSBhcmVhLCBjYW4gc2VlIHRoYXQgbG93ZXIgcHJpY2VzIAp0ZW5kIHRvIGxvY2F0ZWQgdG8gdGhlIHBlcmltZXRlciBvZiBOZXcgWW9yaywgaW5kaWNhdGluZyB0aGF0IGxvY2F0aW9uIHRvd2FyZHMKY2VudHJlIG9mIE1hbmhhdHRhbiBpcyBhIGxhcmdlIGRldGVybWluYW50IG9mIHByaWNlLgoKCiMjIExlYWZsZXQgTWFwCgpgYGB7cn0KIyBkZWZpbmUgY29sb3VyIHBhbGV0dGUgZm9yIG1hcAogcGFsIDwtIGNvbG9yRmFjdG9yKAogICAjIHNlbGVjdCBvd24gY29sb3VyIHNjaGVtZQogICBwYWxldHRlID0gYygib3JhbmdlIiwgIndoaXRlIiwgInllbGxvdyIsICJyZWQiKSwgCiAgICMgc2VsZWN0IHZhcmlhYmxlIGZvciBjb2xvdXIgcGFsZXR0ZQogICBkb21haW4gPSBwcmljZXNfZGYkcHJpY2VfY2xhc3MpCgojIGxlYWZsZXQgbWFwCmxlYWZsZXQoZGF0YSA9IHByaWNlc19uZXcpICU+JSAKICAjIGFkZCBkYXJrIGJhY2tncm91bmQgZm9yIG1hcAogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuRGFya01hdHRlck5vTGFiZWxzKSAlPiUgCiAgIyBhZGQgbWFya2VyIGZvciBlYWNoIEFpcmJuYiBiYXNlZCBvbiBwcmljZV9jbGFzcwogIGFkZENpcmNsZU1hcmtlcnMofmxvbmdpdHVkZSwgfmxhdGl0dWRlLCBjb2xvciA9IH5wYWwocHJpY2VfY2xhc3MpLCB3ZWlnaHQgPSAxLCAKICAgICAgICAgICAgICAgICAgIHJhZGl1cz0xLCBmaWxsT3BhY2l0eSA9IDAuMSwgb3BhY2l0eSA9IDAuMSkgJT4lCiAgIyBhZGQgbGVnZW5kIGZvciBjb2xvdXIgYXNzb2NpYXRlZCB3aXRoIHByaWNlX2NsYXNzCiAgYWRkTGVnZW5kKCJib3R0b21yaWdodCIsIHBhbCA9IHBhbCwgdmFsdWVzID0gfnByaWNlX2NsYXNzLAogICAgICAgICAgICB0aXRsZSA9ICJQcmljZSBDbGFzcyIsCiAgICAgICAgICAgIG9wYWNpdHkgPSAxCiAgKSAKYGBgCgoKTGVhZmxldCBtYXAgc2hvd3MgdGhlIGNvbnRyYXN0IGJldHdlZW4gZXh0cmVtaXRpZXMgYW5kIGNpdHkgY2VudHJlLCBldmlkZW50bHkKbXVjaCBoaWdoZXIgcHJpY2VzIGluIHRoZSBjaXR5LiAKCl9fU3VtbWFyeV9fCgpQcmljZXMgYXJlIGJlaW5nIGltcGFjdGVkIGJ5OgotIGxvY2F0aW9uCi0gdHlwZSBvZiBhY2NvbW1vZGF0aW9uIAoKCiMgTW9kZWwgQnVpbGRpbmcgLSBMaW5lYXIgUmVncmVzc2lvbgoKQXBwcm9hY2g6IAotIG1hbnVhbAotIGdvb2Qgd2F5IHRvIGJlY29tZSBmYW1pbGlhciB3aXRoIGRhdGEKLSBhdm9pZCBvdmVyIG9yIHVuZGVyIGZpdHRpbmcgdGhlIG1vZGVsCgpHb2FscyBvZiB0aGUgbW9kZWw6IAoKLSBBIHdlbGwgZml0IG1vZGVsIHRoYXQgcmVhc29uYWJseSBleHBsYWlucyB2YXJpYW5jZSBpbiBwcmljZQotIHNhdGlzZmllcyBhc3N1bXB0aW9ucyBuZWVkZWQgdG8gdmFsaWRhdGUgbW9kZWwKLSBCZSBhYmxlIHRvIG91dHB1dCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGNvZWZmaWNpZW50cyBmb3IgY29uc3VtZXIvaG9zdApyZWNvbW1lbmRhdGlvbnMKCgojIyBEaXN0cmlidXRpb24gb2YgUHJpY2UKCkRlcGVuZGVudCB2YXJpYWJsZTogUHJpY2UKCkltcG9ydGFudCB0byBpbnZlc3RpZ2F0ZSBpdHMgZGlzdHJpYnV0aW9uIGFzIGl0IG1heSByZXF1aXJlIGEgdHJhbnNmb3JtYXRpb24gdG8gCmNyZWF0ZSBhIGJldHRlciBmaXQgZm9yIHRoZSBtb2RlbAoKCmBgYHtyfQojIGRpc3RyaWJ1dGlvbiBvZiBwcmljZSAKcHJpY2VzX25ldyAlPiUgCiAgIyBzZWxlY3QgcHJpY2UgZm9yIHgtYXhpcwogIGdncGxvdChhZXMocHJpY2UpKSArCiAgIyBzcGVjaWZ5IGhpc3RvZ3JhbQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDAsIGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBmaWxsID0gInJlZCIpICsgCiAgIyBhZGQgaW4gYSBkZW5zaXR5IHBsb3QKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIsIGZpbGwgPSAicmVkIikgKwogICMgdGhlbWUKICB0aGVtZV9idygpICsKICAjIHRpdGxlCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUHJpY2UiKQpgYGAKClByaWNlIGlzIGhlYXZpbHkgc2tld2VkIHRvIHRoZSByaWdodCBpbmRpY2F0ZXMgYSBsb2cgdHJhbnNmb3JtYXRpb24gaXMgbmVlZGVkCnRvIGdldCBhIG5vcm1hbCBiZWxsIHNoYXBlZCBkaXN0cmlidXRpb24KCmBgYHtyfQojIG1lYW4gcHJpY2UgCm1lYW5fcHJpY2UgPC0gcHJpY2VzX25ldyAlPiUgCiAgc3VtbWFyaXNlKG1fcHJpY2UgPSBtZWFuKHByaWNlKSkKCgojIGxvZyBiZWxsIHNoYXBlZCBkaXN0cmlidXRpb24gCnByaWNlc19uZXcgJT4lIAogICMgc2V0IHByaWNlIG9uIHgtYXhpcyBhcyBhIG5hdHVyYWwgbG9nYXJpdGhtCiAgZ2dwbG90KGFlcyhsb2cocHJpY2UpKSkgKwogICMgc3BlY2lmeSBoaXN0b2dyYW0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNDAsIGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBmaWxsID0gInJlZCIpICsgCiAgIyBpbnNlcnQgZGVuc2l0eSBhcmVhCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yLCBmaWxsID0gInJlZCIpICsKICAjIGluc2VydCBsaW5lIHRvIGluZGljYXRlIGF2ZXJhZ2UKICBnZW9tX3ZsaW5lKGRhdGEgPSBtZWFuX3ByaWNlLCBhZXMoeGludGVyY2VwdCA9ICBsb2cobV9wcmljZSkpLCBzaXplID0gMSwgCiAgICAgICAgICAgICBsaW5ldHlwZSA9IDIpICsKICAjIHRoZW1lCiAgdGhlbWVfYncoKSArCiAgIyB0aXRsZQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIGxvZyhwcmljZSkiKQpgYGAKCgoKIyMgRmluYWxpc2luZyBEYXRhIGZvciBNb2RlbAoKRHJvcHBlZCB2YXJpYWJsZXM6CgotICduYW1lJyAtIHVzZSBkdW1teSB2YXJpYWJsZXMgZm9yIGltcG9ydGFudCB3b3JkcyBhbmQgYmlncmFtcyBpbnN0ZWFkCi0gJ25laWdoYm91cmhvb2QnIC0gdXNlIHRoZSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBmb3IgZml2ZSBOZXcgWW9yayBCb3JvdWdocwotICdwcmljZV9jbGFzcycgLSBoaWdoIGNvcnJlbGF0ZWQgd2l0aCBkZXBlbmRlbnQgdmFyaWFibGUgcHJpY2UKCkR1bW15IHZhcmlhYmxlcyBjcmVhdGVkIGZyb20gdGV4dCBhbmFseXNpczogCgotICdhcGFydG1lbnQnCi0gJ3ByaXZhdGUnCi0gJ2NlbnRyYWwgcGFyaycKCmBgYHtyfQpwcmljZXNfcmVnX2RmIDwtIHByaWNlc19uZXcgJT4lIAogICMgY3JlYXRlIGR1bW15IHZhcmlhYmxlcyBmb3IgY2hvc2VuIHdvcmRzIHRoYXQgbWF5IGltcGFjdCBwcmljZQogIG11dGF0ZShhcGFydG1lbnRfYWQgPSBpZl9lbHNlKHN0cl9kZXRlY3QobmFtZSwgIltBYV1wYXJ0bWVudCIpLCAiWUVTIiwgIk5PIiksCiAgICAgICAgIHByaXZhdGVfYWQgPSBpZl9lbHNlKHN0cl9kZXRlY3QobmFtZSwgIltQcF1yaXZhdGUiKSwgIllFUyIsICJOTyIpLAogICAgICAgICBjZW50cmFsX3BhcmtfYWQgPSBpZl9lbHNlKHN0cl9kZXRlY3QobmFtZSwgIltDY11lbnRyYWwgW1BwXWFyayIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiWUVTIiwgIk5PIiksCiAgICAgICAgICkgJT4lIAogICMgcmVtb3ZlIHZhcmlhYmxlcyBub3QgY29uc2lkZXJlZCBmb3IgbW9kZWwKICBkcGx5cjo6c2VsZWN0KC1jKG5hbWUsIG5laWdoYm91cmhvb2QsIHByaWNlX2NsYXNzKSkgJT4lIAogICMgbG9nIHRyYW5zZm9ybSBwcmljZQogIG11dGF0ZShsb2dfcHJpY2UgPSBsb2cocHJpY2UgKyAxKSkgJT4lIAogICMgYnJpbmcgcHJpY2UgdG8gdGhlIGZyb250CiAgZHBseXI6OnNlbGVjdChsb2dfcHJpY2UscHJpY2UsIGV2ZXJ5dGhpbmcoKSkgJT4lIAogICMgY2hhbmdlIGFsbCBjaGFyYWN0ZXIgdmFyaWFibGVzIHRvIGZhY3RvcgogIG11dGF0ZShhY3Jvc3MoLmNvbHMgPSBpcy5jaGFyYWN0ZXIsIAogICAgICAgICAgICAgICAgLmZucyA9IGFzX2ZhY3RvcikpICU+JSAKICAjIHJlbW92ZSBvcmlnaW5hbCBwcmljZSB2YXJpYWJsZQogIGRwbHlyOjpzZWxlY3QoLXByaWNlKQogIApgYGAKCgpDaGVjayBhbGlhcygpIGZ1bmN0aW9uIHRvIGNoZWNrIGZvciBtdWx0aWNvbGxpbmVhcml0eSAKCmBgYHtyfQojIGNoZWNrIGZvciBtdWx0aWNvbGxpbmVhcml0eQphbGlhcyhsbShsb2dfcHJpY2UgfiAuLCBkYXRhID0gcHJpY2VzX3JlZ19kZikpCmBgYAoKRGF0YSBpcyBub3cgcmVhZHkgdG8gYmUgdXNlZCBpbiByZWdyZXNzaW9uIGFuYWx5c2lzCgoKClVzZSBnZ3BhaXJzKCkgdG8gaW52ZXN0aWdhdGUgd2hpY2ggdmFyaWFibGVzIGFyZSBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHByaWNlLgoKRGF0YSBzZXQgaXMgbGFyZ2Ugc28gcmVsYXRpb25zaGlwIGFuYWx5c2lzIHdpbGwgYmUgZGl2aWRlZCBpbnRvIG51bWVyaWMgYW5kIApub24tbnVtZXJpYyBkYXRhdHlwZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CiMgc2VsZWN0IHZhcmlhYmxlcyB0aGF0IGFyZSBudW1lcmljCnZhcmlhYmxlX251bWVyaWMgPC0gcHJpY2VzX3JlZ19kZiAlPiUKICBzZWxlY3RfaWYoaXMubnVtZXJpYykKCiMgZ2dwYWlycyB3aXRoIG9ubHkgbnVtZXJpYyB2YXJpYWJsZXMKZ2dwYWlycyh2YXJpYWJsZV9udW1lcmljKQpgYGAKCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQojIHNlbGVjdCB2YXJpYWJsZXMgdGhhdCBhcmUgY2F0ZWdvcmljYWwgCnZhcmlhYmxlX25vbm51bWVyaWMgPC0gcHJpY2VzX3JlZ19kZiAlPiUKICAjIHVzZSBmdW5jdGlvbiB0byByZXR1cm4gdmFyaWFibGVzIHRoYXQgYXJlIGNhdGVnb3JpY2FsCiAgc2VsZWN0X2lmKGZ1bmN0aW9uKHgpICFpcy5udW1lcmljKHgpKQoKIyBuZWVkIHRvIGFkZCBsb2dfcHJpY2UgdG8gbm9uLW51bWVyaWMgZGF0YSAKdmFyaWFibGVfbm9ubnVtZXJpYyRsb2dfcHJpY2UgPC0gcHJpY2VzX3JlZ19kZiRsb2dfcHJpY2UKCiMgbm9uLW51bWVyaWMgZ2dwYWlycwpnZ3BhaXJzKHZhcmlhYmxlX25vbm51bWVyaWMpCmBgYAoKCiMjIFVuaXZhcmlhdGUgUmVncmVzc2lvbgoKTGFyZ2VzdCBjb3JyZWxhdGlvbiB3aXRoIHByaWNlOiBsb25naXR1ZGUKLSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgYnkgMC4xNTUKLSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGF0IHRoZSAwLjAwMSBsZXZlbCBvZiBzaWduaWZpY2FuY2UuIAoKVGhlIG5vbi1udW1lcmljIGdncGFpcnMgc3VnZ2VzdHMgdGhhdCBzZXZlcmFsIHZhcmlhYmxlcyB3aWxsIGJlIGFibGUgdG8gZXhwbGFpbiAKcHJpY2UgdmFyaWFuY2UuICAKCiMjIyByZWxhdGlvbnNoaXAgYmV0d2VlbiBsb2cocHJpY2UpIGFuZCBsb25naXR1ZGUKCmBgYHtyfQojIHNjYXR0ZXIgcGxvdCBmb3IgbG9nX3ByaWNlIH4gbG9uZ2l0dWRlCnByaWNlc19yZWdfZGYgJT4lIAogIGdncGxvdChhZXMobG9uZ2l0dWRlLCBsb2dfcHJpY2UpKSArIAogICMgc3BlY2lmeSBzY2F0dGVyIHBsb3QKICBnZW9tX3BvaW50KCkgKyAKICAjIGFkZCBpbiBsaW5lYXIgbW9kZWwgbGluZSBvZiBiZXN0IGZpdAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG91ciA9ICJyZWQiKSArCiAgIyB0aGVtZQogIHRoZW1lX2J3KCkgKyAKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIGxvZyhwcmljZSkgYW5kIGxvbmdpdHVkZSIpCmBgYApjcmVhdGUgbW9kZWwKCmBgYHtyfQojIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsCm1vZGVsXzEgPC0gbG0obG9nX3ByaWNlIH4gbG9uZ2l0dWRlLCBkYXRhID0gcHJpY2VzX3JlZ19kZikKYGBgCgoKYGBge3J9CiMgY2hlY2sgcmVncmVzc2lvbiBkaWFnbm9zdGljcwphdXRvcGxvdChtb2RlbF8xKQpgYGAKCgojIyMgUmVncmVzc2lvbiBEaWFnbm9zdGljcyAKCmdyYXBoIDEgKHBvcHVsYXRpb24pIC0gdGVsbCB1cyBtb3N0IG9ic2VydmF0aW9ucyBhcmUgaW5kZXBlbmRlbmNlLCBibHVlIGxpbmUKZGVjbGluZXMgYXQgdGhlIGVuZCBpbmRpY2F0aW5nIG90aGVyIGNodW5rIG9mIG9ic2VydmF0aW9ucyBhcmUgbm90IGluZGVwZW5kZW50bHkKZGlzdHJpYnV0ZWQuIE5lZWQgYW5vdGhlciB2YXJpYWJsZS4KCmdyYXBoIDIgKGRpc3RyaWJ1dGlvbikgLSBzaG93cyBhIGZhaXJseSBub3JtYWwgZGlzdHJpYnV0aW9uLCBhZ2FpbiwgYSBiZW5kIGF0IHRoZQplbmQgaW5kaWNhdGVzIG1vZGVsIG5lZWRzIG1vcmUgdG8gZ2l2ZSBhIGJldHRlciBkaXN0cmlidXRpb24KCmdyYXBoIDMgKGhvbW9za2VkYXN0aWNpdHkpIC0gVGhlcmUgaXMgaGV0ZXJvc2tlZGFzdGljaXR5IGluIHRoZSBtb2RlbCAKaW5kaWNhdGVkIG15IGN1cnZlIG9uIGJsdWUgbGluZSAKCmdyYXBoIDQgKG91dGxpZXJzKSAtIFRoZXJlIGlzIGEgc21hbGwgbnVtYmVyIG9mIG91dGxpZXJzLCBhbmQgcG9pbnRzIGFyZSBub3QKaGlnaGx5IGxldmVyYWdlZC4gCgoKIyMjIG1vZGVsIGludGVycHJldGF0aW9uCgpgYGB7cn0KIyBvYnRhaW4gcmVzdWx0cyBvZiByZWdyZXNzaW9uIG1vZGVsCnN1bW1hcnkobW9kZWxfMSkKYGBgCgpfX2NvZWZmaWNpZW50OiBfXwoKLSBBbiBpbmNyZWFzZSBpbiBsb25naXR1ZGUgYnkgb25lIHVuaXQgaXMgYXNzb2NpYXRlZCB3aXRoIGEgY2hhbmdlIGluIHByaWNlIGJ5IApfXzk5LjklX18gb24gYXZlcmFnZS4gCgpSLXNxdWFyZWQgLSBsb25naXR1ZGUgZXhwbGFpbnMgMTAuNiUgb2YgdGhlIHZhcmlhbmNlIG9mIGFpcmJuYiBwcmljZS4gCgoKCiMjIE11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uCgpGcm9tIHRoZSBnZ3BhaXJzIHBsb3QgYW5kIHByZXZpb3VzIGFuYWx5c2lzLCBuZWlnaGJvdXJob29kX2dyb3VwIGlzIHN1Z2dlc3RzIApoYXZpbmcgYW4gaW1wYWN0IG9uIGFpcmJuYiBwcmljZXMsIEkgd2lsbCBhZGQgdGhpcyBuZXh0LiAKCgoKIyMgUmVsYXRpb25zaGlwIGJldHdlZW4gUHJpY2UgYW5kIEJvcm91Z2gKCmBgYHtyfQojIHJlbGF0aW9uc2hpcCBsb2cocHJpY2UpIH4gYm9yb3VnaApwcmljZXNfcmVnX2RmICU+JSAKICBnZ3Bsb3QoYWVzKG5laWdoYm91cmhvb2RfZ3JvdXAsIGxvZ19wcmljZSwgZmlsbCA9IG5laWdoYm91cmhvb2RfZ3JvdXApKSArIAogICMgc3BlY2lmeSBib3hwbG90CiAgZ2VvbV9ib3hwbG90KHNob3cubGVnZW5kID0gRkFMU0UpICsKICAjIHRoZW1lCiAgdGhlbWVfYncoKSArIAogICMgdGl0bGUKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIFByaWNlIGFuZCBCb3JvdWdoIikKYGBgCgpgYGB7cn0KIyBsaW5lYXIgbW9kZWwgMgptb2RlbF8yIDwtIGxtKGxvZ19wcmljZSB+IGxvbmdpdHVkZSArIG5laWdoYm91cmhvb2RfZ3JvdXAsIGRhdGEgPSBwcmljZXNfcmVnX2RmKQpgYGAKCgpgYGB7cn0KIyByZWdyZXNzaW9uIGRpYWdub3N0aWNzCmF1dG9wbG90KG1vZGVsXzIpCmBgYAoKCiMjIyByZWdyZXNzaW9uIGRpYWdub3N0aWNzCgpncmFwaCAxIC0gaW5kZXBlbmRlbnQgcG9wdWxhdGlvbiAoYWNoaWV2ZWQpCmdyYXBoIDIgLSBzdGlsbCBhIHNrZXcgaW4gZGlzdHJpYnV0aW9uCmdyYXBoIDMgLSBIb21vc2tkYXN0aWNpdHkgKGFjaGlldmVkKQpncmFwaCA0IC0gTm8gaGlnaGx5IGxldmVyYWdlZCBwb2ludHMsIGJ1dCB0aGVyZSBhcmUgc3RpbGwgKHBvdGVudGlhbGx5KSBhIGZldyAKb3V0bGllcnMKCgojIyMgbW9kZWwgaW50ZXJwcmV0YXRpb24KCmBgYHtyfQojIHJlZ3Jlc3Npb24gcmVzdWx0cwpzdW1tYXJ5KG1vZGVsXzIpCmBgYAoKX19jb2VmZmljaWVudHM6X18gCgotIGFsbCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGF0IGxldmVscyBvZiBzaWduaWZpY2FuY2UgLSBjYW4gcmVqZWN0IHRoZSBudWxsCmh5cG90aGVzaXMgYW5kIHNheSB0aGF0IGNvZWZmaWNpZW50cyBhcmUgc3RhdGlzdGljYWxseSBkaWZmZXJlbnQgZnJvbSB6ZXJvLiAKCi0gIEFuIGluY3JlYXNlIGluIE1hbmhhdHRhbiBieSBvbmUgdW5pdCAoemVybyB0byBvbmUpIGlzIGFzc29jaWF0ZWQgd2l0aCBhIApjaGFuZ2UgaW4gcHJpY2UgYnkgKGVeMC4yNy0xKSAqIDEwMCA9IF9fMzElX18sIGhvbGRpbmcgYWxsIG90aGVyIGZhY3RvcnMgCmNvbnN0YW50IAoKLSBBbiBpbmNyZWFzZSBpbiBTdGF0ZW4gSXNsYW5kIGJ5IG9uZSB1bml0ICh6ZXJvIHRvIG9uZSkgaXMgYXNzb2NpYXRlZCB3aXRoIGEgCmNoYW5nZSBpbiBwcmljZSBieSAoZV4tMC45NCAtIDEpICogMTAwID0gX18tNjAuOSVfXywgaG9sZGluZyBhbGwgb3RoZXIgZmFjdG9ycyAKY29uc3RhbnQKCgojIyMgQW5vdmEgZnVuY3Rpb24KCmBgYHtyfQojIGZ1bmN0aW9uIHRvIGNoZWNrIGlmIGR1bW15IHZhcmlhYmxlcyBhcmUgdXNlZnVsCmFub3ZhKG1vZGVsXzEsIG1vZGVsXzIpCmBgYAoKYW5vdmEgZnVuY3Rpb24gY29uZmlybXMgdGhlIG5laWdoYm91cmhvb2RfZ3JvdXAgZHVtbXkgdmFyaWFibGUgd2FzIGdvb2QgdG8gaW5jbHVkZQppbiB0aGUgbW9kZWwuIAoKCiMjIE1vZGVsIDMgCgpiZWZvcmUgYWRkaW5nIGEgbmV3IHZhcmlhYmxlLCBtdXN0IGNoZWNrIHRoZSByZXNpZHVhbHMgb2YgdGhpcyBtb2RlbCBhZ2FpbnN0IHRoZQpyZW1haW5pbmcgdmFyaWFibGVzIGluIHRoZSBkYXRhc2V0CgoKIyMjIGNoZWNrIHJlc2lkdWFscwoKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CgojIG9idGFpbiByZXNpZHVhbHMgb2YgbW9kZWwgMgpyZXNpZHVhbHMgPC0gcHJpY2VzX3JlZ19kZiAlPiUgCiAgIyBhZGQgaW4gcmVzaWR1YWxzIHRvIGRhdGFzZXQKICBhZGRfcmVzaWR1YWxzKG1vZGVsXzIpICU+JSAKICAjIHJlbW92ZSB2YXJpYWJsZXMgYWxyZWFkeSBpbiB0aGUgbW9kZWwKICBkcGx5cjo6c2VsZWN0KC1jKGxvZ19wcmljZSwgbG9uZ2l0dWRlLCBuZWlnaGJvdXJob29kX2dyb3VwKSkKYGBgCgoKYGBge3IgbWVzc2FnZSA9IEZBTFNFfQojIHNlcGVyYXRlIGludG8gbnVtZXJpYyBhbmQgbm9uLW51bWVyaWMgCgojIG51bWVyaWMgZGF0YQpwcmljZV9yZXNpZF9udW1lcmljIDwtIHJlc2lkdWFscyAlPiUKICBzZWxlY3RfaWYoaXMubnVtZXJpYykKCiMgbm9uLW51bWVyaWMgZGF0YQpwcmljZV9yZXNpZF9ub25udW1lcmljIDwtIHJlc2lkdWFscyAlPiUKICBzZWxlY3RfaWYoZnVuY3Rpb24oeCkgIWlzLm51bWVyaWMoeCkpCgojIGFkZCByZXNpZHVkYWxzIHRvIG5vbi1udW1lcmljIGRhdGEKcHJpY2VfcmVzaWRfbm9ubnVtZXJpYyRyZXNpZCA8LSByZXNpZHVhbHMkcmVzaWQKCiMgbm93IHJlYWR5IGZvciBjb21wYXJpbmcgbW9kZWwgcmVzaWR1YWxzIHRvIHJlc3Qgb2YgZGF0YQoKIyBudW1lcmljIGdncGFpcnMKZ2dwYWlycyhwcmljZV9yZXNpZF9udW1lcmljKQpgYGAKCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQojIG5vbi1udW1lcmljIGdncGFpcnMKZ2dwYWlycyhwcmljZV9yZXNpZF9ub25udW1lcmljKQpgYGAKCgpGcm9tIG51bWVyaWMgdmFyaWFibGVzLCBhdmFpbGFiaWxpdHlfMzY1IGhhcyB0aGUgaGlnaGVzdCBjb3JyZWxhdGlvbiB3aXRoIHByaWNlCmEgcG9zaXRpdmUgY29ycmVsYXRpb24gb2YgMC4xMzEgKHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQpLiAKCkhvd2V2ZXIsIHRoZSBub24tbnVtZXJpYyB2YXJpYWJsZXMgaW5kaWNhdGUgdGhhdCByb29tIHR5cGUgbWF5IHByZXNlbnQgYSBiZXR0ZXIKZXhwbGFuYXRpb24gb2YgcHJpY2UgdmFyaWFuY2UuIAoKCiMjIyBDb21wYXJpc29uIGJldHdlZW4gaW1wYWN0IG9mIFJvb20gVHlwZSBhbmQgQXZhaWxhYmlsaXR5IG9uIFByaWNlCgpgYGB7cn0KIyByZWxhdGlvbnNoaXAgcmVzaWR1YWxzIH4gcm9vbSBhdmFpbGFiaWxpdHkKYXZhaWxfcGxvdCA8LSBwcmljZV9yZXNpZF9udW1lcmljICU+JSAKICBnZ3Bsb3QoYWVzKGF2YWlsYWJpbGl0eV8zNjUsIHJlc2lkKSkgKyAKICAjIHNjYXR0ZXIgcGxvdCAKICBnZW9tX3BvaW50KCkgKwogICMgaW5zZXJ0IGxpbmVhciBtb2RlbCBsaW5lIG9mIGJlc3QgZml0CiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3VyID0gInJlZCIpICsgCiAgIyB0aGVtZQogIHRoZW1lX2J3KCkgKwogICMgdGl0bGVzCiAgbGFicyh4ID0gIlllYXJseSBSb29tIEF2YWlsYWJpbGl0eSIsIHkgPSAiUmVzaWR1YWxzIiwgCiAgICAgICB0aXRsZSA9ICJSZWxhdGlvbnNoaXAgUmVzaWR1YWxzIGFuZCBBdmFpbGFiaWxpdHkiKSArCiAgIyBhZGp1c3QgdGl0bGUgZm9udCBzaXplCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkKCgojIHJlbGF0aW9uc2hpcCByZXNpZHVhbHMgfiByb29tX3R5cGUKcm9vbV90eXBlX3Bsb3QgPC0gcHJpY2VfcmVzaWRfbm9ubnVtZXJpYyAlPiUgCiAgZ2dwbG90KGFlcyhyb29tX3R5cGUsIHJlc2lkLCBmaWxsID0gcm9vbV90eXBlKSkgKyAKICAjIGJveHBsb3QKICBnZW9tX2JveHBsb3Qoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICMgdGhlbWUKICB0aGVtZV9idygpICsgCiAgIyB0aXRsZXMgCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgUmVzaWR1YWxzIGFuZCBSb29tIFR5cGUiLAogICAgICAgeCA9ICJSb29tIFR5cGUiLCB5ID0gIlJlc2lkdWFscyIpICsKICAjIGFkanVzdCB0aXRsZSBmb250IHNpemUKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQoKCiMgcGxvdCBib3RoIHZpc3VhbHMgdG9nZXRoZXIKY293cGxvdDo6cGxvdF9ncmlkKGF2YWlsX3Bsb3QsIHJvb21fdHlwZV9wbG90LCBucm93ID0gMSkgCmBgYAoKVGhlIGNvbXBhcmlzb24gc3VnZ2VzdHMgcm9vbSB0eXBlIHNob3VsZCBvZmZlciBtb3JlIGV4cGxhbmF0aW9uLiAKCgpgYGB7cn0KIyBsaW5lYXIgbW9kZWwgMwptb2RlbF8zIDwtIGxtKGxvZ19wcmljZSB+IGxvbmdpdHVkZSArIG5laWdoYm91cmhvb2RfZ3JvdXAgKyByb29tX3R5cGUsIAogICAgICAgICAgICAgIGRhdGEgPSBwcmljZXNfcmVnX2RmKQpgYGAKCgpgYGB7cn0KIyBjaGVjayBtb2RlbCBkaWFnbm9zdGljcwphdXRvcGxvdChtb2RlbF8zKQpgYGAKCgpncmFwaCAxIC0gcmVzaWR1YWxzIGFyZSBpbmRlcGVuZGVudApncmFwaCAyIC0gdGhlIHJlc2lkdWFscyBzZWVtIHRvIGJlIGluY3JlYXNpbmdseSBub3QgZGlzdHJpYnV0ZWQgYXJvdW5kIHplcm8Kd2l0aCBtb3JlIHNrZXcgYXQgdGhlIGJlZ2lubmluZyBhbmQgZW5kCmdyYXBoIDMgLSBjb25kaXRpb25hbCB2YXJpYW5jZSBvZiByZXNpZHVhbHMgaXMgY29uc3RhbnQgKGhvbW9za2VkYXN0aWNpdHkpCgoKYGBge3J9CiMgbW9kZWwgcmVzdWx0cwpzdW1tYXJ5KG1vZGVsXzMpCmBgYAoKCkFzIGFudGljaXBhdGVkLCByb29tX3R5cGUgZ3JlYXRseSBlbmhhbmNlZCB0aGUgZXhwbGFuYXRpb24gb2YgdGhlIG1vZGVsLiBUaGUgClItc3F1YXJlZCBzdWdnZXN0cyB0aGUgbW9kZWwgZXhwbGFpbnMgNDkuMyUgb2YgdGhlIHZhcmlhbmNlIGluIHByaWNlLiAKClRoZSB2YXJpYWJsZSBjb2VmZmljaWVudHMgYXJlIGFsbCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHRoZXJlZm9yZSBjYW4gYmUKaW50ZXJwcmV0ZWQuIAoKCiMjIE1vZGVsIDQKCiMjIyBDaGVjayByZXNpZHVhbHMKCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQojIGNvbXBhcmUgbW9kZWwgcmVzaWR1YWxzIHRvIHJlbWFpbmluZyBkYXRhCnJlc2lkdWFscyA8LSBwcmljZXNfcmVnX2RmICU+JSAKICAjIGFkZCByZXNpZHVhbHMKICBhZGRfcmVzaWR1YWxzKG1vZGVsXzMpICU+JSAKICAjIHJlbW92ZSB2YXJpYWJsZXMgaW4gbW9kZWwKICBkcGx5cjo6c2VsZWN0KC1jKGxvZ19wcmljZSwgbG9uZ2l0dWRlLCBuZWlnaGJvdXJob29kX2dyb3VwLCByb29tX3R5cGUpKQpgYGAKCgpgYGB7ciBtZXNzYWdlID0gRkFMU0V9CgojIHNlcGVyYXRlIGludG8gbnVtZXJpYyBhbmQgbm9uLW51bWVyaWMgCgojIG51bWVyaWMgZGF0YQpwcmljZV9yZXNpZF9udW1lcmljIDwtIHJlc2lkdWFscyAlPiUKICBzZWxlY3RfaWYoaXMubnVtZXJpYykKCiMgbm9uLW51bWVyaWMgZGF0YQpwcmljZV9yZXNpZF9ub25udW1lcmljIDwtIHJlc2lkdWFscyAlPiUKICBzZWxlY3RfaWYoZnVuY3Rpb24oeCkgIWlzLm51bWVyaWMoeCkpCgoKIyBhZGQgcmVzaWR1YWxzIHRvIG5vbi1udW1lcmljIGRhdGEKcHJpY2VfcmVzaWRfbm9ubnVtZXJpYyRyZXNpZCA8LSByZXNpZHVhbHMkcmVzaWQKCiMgbnVtZXJpYyBnZ3BhaXJzCmdncGFpcnMocHJpY2VfcmVzaWRfbnVtZXJpYykKYGBgCgoKYGBge3IgbWVzc2FnZSA9IEZBTFNFfQojIG5vbi1udW1lcmljIGdncGFpcnMKZ2dwYWlycyhwcmljZV9yZXNpZF9ub25udW1lcmljKQpgYGAKCgpBcyBiZWZvcmUsIGF2YWlsYWJpbGl0eSBpcyBkaXNwbGF5aW5nIGJ5IGZhciB0aGUgc3Ryb25nZXN0IGNvcnJlbGF0aW9uLCBhbmQgdGhlcmUKZG9lcyBub3Qgc2VlbSB0byBiZSBhbnkgc3RhbmQgb3V0IG5vbi1udW1lcmljIHZhcmlhYmxlcy4gVGhlcmVmb3JlLCByb29tIAphdmFpbGFiaWxpdHkgd2lsbCBiZSB1c2VkIGluIHRoZSBuZXh0IG1vZGVsLiAKCgpgYGB7cn0KIyBsaW5lYXIgbW9kZWwgNAptb2RlbF80IDwtIGxtKGxvZ19wcmljZSB+IGxvbmdpdHVkZSArIG5laWdoYm91cmhvb2RfZ3JvdXAgKyByb29tX3R5cGUgKyAKICAgICAgICAgICAgICAgIGF2YWlsYWJpbGl0eV8zNjUsIGRhdGEgPSBwcmljZXNfcmVnX2RmKQpgYGAKCgoKYGBge3J9CiMgY2hlY2sgbW9kZWwgZGlhZ25vc3RpY3MKYXV0b3Bsb3QobW9kZWxfNCkKYGBgCgpncmFwaCAxIC0gbW9kZWwgcG9wdWxhdGlvbiBpcyBpbmRlcGVuZGVudGx5IGRpc3RyaWJ1dGVkCmdyYXBoIDIgLSBzdGlsbCBza2V3IGF0IGJvdGggZW5kcyBvZiBncmFwaCwgaW5kaWNhdGluZyBncmFwaCBpcyBvbmx5IHNvbWV3aGF0Cm5vcm1hbGx5IGRpc3RyaWJ1dGVkCmdyYXBoIDMgLSBjb25kaXRpb25hbCB2YXJpYW5jZSBvZiByZXNpZHVhbHMgaXMgY29uc3RhbnQgKGhvbW9za2VkYXN0aWMpCgoKCmBgYHtyfQojIG1vZGVsIHJlc3VsdHMKc3VtbWFyeShtb2RlbF80KQpgYGAKCgpSLXNxdWFyZWQgaGFzIG9ubHkgaW5jcmVhc2VkIG1hcmdpbmFsbHkgdG8gMC41MSAtIG1vZGVsIGV4cGxhaW5zIDUxJSBvZiB0aGUgCnZhcmlhbmNlIGluIHByaWNlCgpBbGwgdmFyaWFibGVzIGluIHRoZSBtb2RlbCBhcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudAoKCgojIyBBZGRpbmcgYW4gaW50ZXJhY3Rpb24gdGVybQoKcG90ZW50aWFsIHRlcm1zOgoKLSBsb25naXR1ZGU6bmVpZ2hib3VyaG9vZF9ncm91cAotIGxvbmdpdHVkZTpyb29tX3R5cGUKLSBsb25naXR1ZGU6YXZhaWxhYmlsaXR5XzM2NQotIG5laWdoYm91cmhvb2RfZ3JvdXA6cm9vbV90eXBlCi0gbmVpZ2hib3VyaG9vZF9ncm91cDphdmFpbGFiaWxpdHlfMzY1Ci0gcm9vbV90eXBlOmF2YWlsYWJpbGl0eV8zNjUKCgpUaHJvdWdoIHByb2Nlc3Mgb2YgZWxpbWluYXRpb24sIGxvbmdpdHVkZTpuZWlnaGJvdXJob29kX2dyb3VwIAoKYGBge3J9CiMgbGluZWFyIG1vZGVsIDUgLSB3aXRoIGludGVyYWN0aW9uIHRlcm0KbW9kZWxfNSA8LSBsbShsb2dfcHJpY2UgfiBsb25naXR1ZGUgKyBuZWlnaGJvdXJob29kX2dyb3VwICsgcm9vbV90eXBlICsgCiAgICAgICAgICAgICAgICBhdmFpbGFiaWxpdHlfMzY1ICsgbG9uZ2l0dWRlOm5laWdoYm91cmhvb2RfZ3JvdXAsCiAgICAgICAgICAgICAgZGF0YSA9IHByaWNlc19yZWdfZGYpCmBgYAoKCiMjIyBQbG90dGluZyB0aGUgaW50ZXJhY3Rpb24gCgpgYGB7cn0KIyBhZGQgbW9kZWwgcmVzaWR1YWxzIHRvIGRhdGEKcHJpY2VfcmVzaWQgPC0gcHJpY2VzX3JlZ19kZiAlPiUgCiAgIyBhZGQgbW9kZWwgcmVzaWR1YWxzCiAgYWRkX3Jlc2lkdWFscyhtb2RlbF81KSAlPiUgCiAgIyByZW1vdmUgbG9nX3ByaWNlCiAgZHBseXI6OnNlbGVjdCgtbG9nX3ByaWNlKQoKCiMgY2hlY2sgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gbG9uZ2l0dWRlIGFuZCBuZWlnaGJvdXJob29kX2dyb3VwCmNvcGxvdChyZXNpZCB+IGxvbmdpdHVkZSB8IG5laWdoYm91cmhvb2RfZ3JvdXAsCiAgICAgICAjIGdpdmUgYW4gYWN0aW9uIHRvIGJlIGNhcnJpZWQgb3V0IGluIGVhY2ggcGFuZWwKICAgICAgIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKXsKICAgICAgICAgIyBwbG90IGNvb3JkaW5hdGVzIG9mIHggYW5kIHkKICAgICAgICAgcG9pbnRzKHgsIHkpCiAgICAgICAgICMgaW5zZXJ0IGxpbmVhciBtb2RlbCBsaW5lCiAgICAgICAgIGFibGluZShsbSh5IH4geCksIGNvbCA9ICJibHVlIikKICAgICAgIH0sCiAgICAgICBkYXRhID0gcHJpY2VfcmVzaWQsIHJvd3MgPSAxKQpgYGAKCgojIyMgTW9kZWwgRGlhZ25vc3RpY3MKCmBgYHtyfQojIHJlZ3Jlc3Npb24gZGlhZ25vc3RpY3MKYXV0b3Bsb3QobW9kZWxfNSkKYGBgCgpncmFwaCAxIC0gcG9wdWxhdGlvbiBpcyBpbmRlcGVuZGVudApncmFwaCAyIC0gbW9kZWwgc3RpbGwgbm90IGNvbXBsZXRlbHkgZXZlbmx5IGRpc3RyaWJ1dGVkIGFyb3VuZCAwCmdyYXBoIDMgLSBjb25kaXRpb25hbCB2YXJpYW5jZSBvZiByZXNpZHVhbHMgaXMgY29uc3RhbnQgKGhvbW9za2VkYXN0aWNpdHkpCmdyYXBoIDQgLSB0aGVyZSBhcmUgc3RpbGwgc29tZSBvdXRsaWVycywgYnV0IG5vIGhpZ2hseSBsZXZlcmFnZWQgcG9pbnRzCgoKIyMjIE1vZGVsIFN1bW1hcnkKCmBgYHtyfQojIG1vZGVsIHJlc3VsdHMKc3VtbWFyeShtb2RlbF81KQpgYGAKX19Nb2RlbCBTdW1tYXJ5Ol9fCgotIEFsbCBleHBsYW5hdG9yeSB2YXJpYWJsZXMgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQKCi0gUi1zcXVhcmVkOiBtb2RlbCBleHBsYWlucyA1Mi41JSBvZiB2YXJpYW5jZSBpbiBwcmljZQogIC0gbW9kZWwgc3VmZmljZXMgYXMgYW4gb2sgZXhwbGFuYXRpb24KICAKLSBSb29tX3R5cGUgaGFkIHRoZSBncmVhdGVzdCBpbmZsdWVuY2Ugb24gdGhlIG1vZGVsCiAgLSBpbnRlcnByZXQgdGhlIGNvZWZmaWNpZW50IGZvciByb29tX3R5cGUtIGVudGlyZS9hcHQ6CiAgICAtIEFuIGluY3JlYXNlIGluIGVudGlyZS9hcHQgYnkgb25lIHVuaXQgKHplcm8gdG8gb25lKSBpcyBhc3NvY2lhdGVkIHdpdGggYSAKY2hhbmdlIGluIHByaWNlIGJ5IChlXjAuNzMtMSkgKiAxMDAgPSBfXzEwNy41JV9fLCBob2xkaW5nIGFsbCBvdGhlciBmYWN0b3JzIApjb25zdGFudAoKCiMjIyBWYXJpYWJsZSByZWxhdGl2ZSBpbXBvcnRhbmNlIAoKYGBge3IgbWVzc2FnZT1GQUxTRX0KCiMgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHZhcmlhYmxlIGltcG9ydGFuY2UKY2FsYy5yZWxpbXAobW9kZWxfNSwgdHlwZSA9ICJsbWciLCByZWxhID0gVFJVRSkKYGBgCgpfX1ZhcmlhYmxlcyBvZiByZWxhdGl2ZSBpbXBvcnRhbmNlOl9fIAoKUm9vbSB0eXBlLCBwZXJoYXBzIHVuc3VycHJpc2luZ2x5LCBpcyB0aGUgbW9zdCByZWxldmFudCB2YXJpYWJsZSBmb3IgZXhwbGFpbmluZwp2YXJpYXRpb25zIGluIHByaWNlLiAKVGhlIGxlYXN0IGV4cGxhbmF0b3J5IGlzIGF2YWlsYWJpbGl0eV8zNjUKCgojIENvbmNsdXNpb24gYW5kIFJlY29tbWVuZGF0aW9ucwoKX19Gb3IgQ29uc3VtZXJzOl9fIAoKLSBUaGUgcm9vbSB0eXBlIGFkdmVydGlzZWQgaXMgdmVyeSBpbXBvcnRhbnQgdG8gZGV0ZXJtaW5pbmcgdGhlIHByaWNlIHlvdSBwYXkKLSBsb2NhdGlvbiBhbmFseXNpcyBzdWdnZXN0cyBjaXR5IGNlbnRyZSBhcmVhcyBkZW1hbmQgbXVjaCBoaWdoZXIgcHJpY2VzIHRoYW4gCm91dHNraXJ0IGFyZWFzIHN1Y2ggYXMgU3RhdGVuIElzbGFuZAoKX19Gb3IgaG9zdHM6X18gCi0gSG93IHlvdSBkZXNjcmliZSB5b3VyIHByb3BlcnR5IGRvZXNuJ3QgdHJhbnNsYXRlIHRvIGJlaW5nIGFibGUgdG8gY2hhcmdlCmhpZ2hlciBwcmljZXMKLSB3aWxsIGJlIGFibGUgdG8gY2hhcmdlIGEgbXVjaCBoaWdoZXIgcHJpY2UgZm9yIHByb3BlcnR5IGxpc3RlZCBhcyB3aG9sZSBhcGFydG1lbnQKLSBwcm9wZXJ0eSBhdmFpbGFiaWxpdHkgZG9lcyBub3QgaGF2ZSBtdWNoIGltcGFjdCBvbiBwcmljZQoKCiMgRnV0dXJlIGFuYWx5c2lzCgpNb3JlIGRhdGEgb246CgoteWVhcmx5IGRhdGEKICAtIHRpbWUtc2VyaWVzIGFuYWx5c2lzCiAgICAtIGlkZW50aWZ5IGN5Y2xpY2FsIHRyZW5kcw==